<!DOCTYPE html>
<html>
<head>
  <meta charset="utf-8">
  
  <title>xSocket系列二之源码分析一 | Hexo</title>
  <meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1">
  <meta name="description" content="简介　　在上一篇文章中，我们采用xSocket开发了一个简单的示例，实现了客户端和服务端通过tcp进行通信的例子，下面我们将根据该例子讲解其中涉及到的几个重要类，对xSocket源码进行简单分析：　　1. Server： 服务器端初始化线程池创建IoAcceptor　　2. IoAcceptor：采用while循环接收客户端连接,并创建IoSocketDispatcher和IoChainableH">
<meta property="og:type" content="article">
<meta property="og:title" content="xSocket系列二之源码分析一">
<meta property="og:url" content="http://yoursite.com/2016/01/02/nio/9.xSocket系列二之源码分析一/index.html">
<meta property="og:site_name" content="Hexo">
<meta property="og:description" content="简介　　在上一篇文章中，我们采用xSocket开发了一个简单的示例，实现了客户端和服务端通过tcp进行通信的例子，下面我们将根据该例子讲解其中涉及到的几个重要类，对xSocket源码进行简单分析：　　1. Server： 服务器端初始化线程池创建IoAcceptor　　2. IoAcceptor：采用while循环接收客户端连接,并创建IoSocketDispatcher和IoChainableH">
<meta property="og:updated_time" content="2016-01-29T17:47:36.000Z">
<meta name="twitter:card" content="summary">
<meta name="twitter:title" content="xSocket系列二之源码分析一">
<meta name="twitter:description" content="简介　　在上一篇文章中，我们采用xSocket开发了一个简单的示例，实现了客户端和服务端通过tcp进行通信的例子，下面我们将根据该例子讲解其中涉及到的几个重要类，对xSocket源码进行简单分析：　　1. Server： 服务器端初始化线程池创建IoAcceptor　　2. IoAcceptor：采用while循环接收客户端连接,并创建IoSocketDispatcher和IoChainableH">
  
    <link rel="alternative" href="/atom.xml" title="Hexo" type="application/atom+xml">
  
  
    <link rel="icon" href="/favicon.png">
  
  <link href="//fonts.googleapis.com/css?family=Source+Code+Pro" rel="stylesheet" type="text/css">
  <link rel="stylesheet" href="/css/style.css" type="text/css">
  

</head>
<body>
  <div id="container">
    <div id="wrap">
      <header id="header">
  <div id="banner"></div>
  <div id="header-outer" class="outer">
    <div id="header-title" class="inner">
      <h1 id="logo-wrap">
        <a href="/" id="logo">Hexo</a>
      </h1>
      
    </div>
    <div id="header-inner" class="inner">
      <nav id="main-nav">
        <a id="main-nav-toggle" class="nav-icon"></a>
        
          <a class="main-nav-link" href="/">Home</a>
        
          <a class="main-nav-link" href="/archives">Archives</a>
        
      </nav>
      <nav id="sub-nav">
        
          <a id="nav-rss-link" class="nav-icon" href="/atom.xml" title="RSS Feed"></a>
        
        <a id="nav-search-btn" class="nav-icon" title="Search"></a>
      </nav>
      <div id="search-form-wrap">
        <form action="//google.com/search" method="get" accept-charset="UTF-8" class="search-form"><input type="search" name="q" results="0" class="search-form-input" placeholder="Search"><button type="submit" class="search-form-submit">&#xF002;</button><input type="hidden" name="sitesearch" value="http://yoursite.com"></form>
      </div>
    </div>
  </div>
</header>
      <div class="outer">
        <section id="main"><article id="post-nio/9.xSocket系列二之源码分析一" class="article article-type-post" itemscope itemprop="blogPost">
  <div class="article-meta">
    <a href="/2016/01/02/nio/9.xSocket系列二之源码分析一/" class="article-date">
  <time datetime="2016-01-02T01:00:00.000Z" itemprop="datePublished">2016-01-02</time>
</a>
    
  <div class="article-category">
    <a class="article-category-link" href="/categories/nio/">nio</a>
  </div>

  </div>
  <div class="article-inner">
    
    
      <header class="article-header">
        
  
    <h1 class="article-title" itemprop="name">
      xSocket系列二之源码分析一
    </h1>
  

      </header>
    
    <div class="article-entry" itemprop="articleBody">
      
        <h2 id="u7B80_u4ECB"><a href="#u7B80_u4ECB" class="headerlink" title="简介"></a>简介</h2><p>　　在上一篇文章中，我们采用xSocket开发了一个简单的示例，实现了客户端和服务端通过tcp进行通信的例子，下面我们将根据该例子讲解其中涉及到的几个重要类，对xSocket源码进行简单分析：<br>　　1. Server： 服务器端初始化线程池创建IoAcceptor<br>　　2. IoAcceptor：采用while循环接收客户端连接,并创建IoSocketDispatcher和IoChainableHandler<br>　　3. IoSocketDispatcher：负责注册SelectionKey以及事件的分发，并交给IoChainableHandler处理，通过一个while循环来处理注册的SelectionKey事件。因为不同平台的Selector实现差异比较大，通常会使用多个（大部分服务器用了两个），用一个Dispatcherpool维护，主要负责检测SocketChannel的注册、以及读写事件。需要注意Selector的key set不是线程安全的，不同线程中更新、读取需要同步。<br>　　4. IHandler：事件处理，数据的读写等等。<br>　　5. INonBlockingConnection客户端接口。</p>
<p>　　这里我们先直接列出服务端监听客户端连接并监听数据的整个过程：<br>　　1. IoAcceptor负责监听客户端的连接，为每个连接新建一个对应的IoSocketHandler，再将它注册到IoSocketDispatcher（内部注册到Selector中）<br>　　2. IoSocketDispatcher负责监听客户端数据的发送，交由 IoSocketHandlder 执行数据的读取操作。<br>　　3. IoSocketHandlder将读取到的数据通过回调，执行NonBlockingConnection的onData和onPostData方法，其中onData将数据交给ReadQueue保存。而onPostData方法则会调用HadlerAdapter的onData方法，它新建一个Runnable放入SerializationTaskQueue中内部的一个链表，并启动一个while循环，获取链表中的Runnable交给WorkQueue执行，最后执行我们定义的IHandler类。<br>　　服务端发送数据时，则将每次发送的数据写入WriteQueue中，并实时从写队列中获取一个数据交由IWriteTask写入socketchannel中</p>
<h2 id="Server"><a href="#Server" class="headerlink" title="Server"></a>Server</h2><p>　　首先我们看看Server类，它实现了接口IServer，而IServer又继承了接口java.lang.Runnable，所以可以理解它为线程。首先我们看看Server的源码，并重点关注其构造方法和start方法的实现。<br><figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br><span class="line">50</span><br><span class="line">51</span><br><span class="line">52</span><br><span class="line">53</span><br><span class="line">54</span><br><span class="line">55</span><br><span class="line">56</span><br><span class="line">57</span><br><span class="line">58</span><br><span class="line">59</span><br><span class="line">60</span><br><span class="line">61</span><br><span class="line">62</span><br><span class="line">63</span><br><span class="line">64</span><br><span class="line">65</span><br><span class="line">66</span><br><span class="line">67</span><br><span class="line">68</span><br><span class="line">69</span><br><span class="line">70</span><br><span class="line">71</span><br><span class="line">72</span><br><span class="line">73</span><br><span class="line">74</span><br><span class="line">75</span><br><span class="line">76</span><br><span class="line">77</span><br><span class="line">78</span><br><span class="line">79</span><br><span class="line">80</span><br><span class="line">81</span><br><span class="line">82</span><br><span class="line">83</span><br><span class="line">84</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">public</span> <span class="class"><span class="keyword">class</span> <span class="title">Server</span> <span class="keyword">implements</span> <span class="title">IServer</span> </span>&#123;</span><br><span class="line">    <span class="keyword">protected</span> <span class="keyword">static</span> <span class="keyword">final</span> <span class="keyword">int</span> SIZE_WORKER_POOL = Integer.parseInt(System.getProperty(<span class="string">"org.xsocket.connection.server.workerpoolSize"</span>, <span class="string">"100"</span>));</span><br><span class="line">    <span class="keyword">protected</span> <span class="keyword">static</span> <span class="keyword">final</span> <span class="keyword">int</span> MIN_SIZE_WORKER_POOL = Integer.parseInt(System.getProperty(<span class="string">"org.xsocket.connection.server.workerpoolMinSize"</span>, <span class="string">"2"</span>));</span><br><span class="line">    <span class="keyword">protected</span> <span class="keyword">static</span> <span class="keyword">final</span> <span class="keyword">int</span> TASK_QUEUE_SIZE = Integer.parseInt(System.getProperty(<span class="string">"org.xsocket.connection.server.taskqueuesize"</span>, Integer.toString(SIZE_WORKER_POOL)));</span><br><span class="line"></span><br><span class="line">    <span class="keyword">private</span> <span class="keyword">static</span> <span class="keyword">final</span> <span class="keyword">int</span> WAITTIME_MAXCONNECTION_EXCEEDED = Integer.parseInt(System.getProperty(<span class="string">"org.xsocket.connection.server.waittimeMaxConnectionExceeded"</span>, Integer.toString(<span class="number">500</span>)));</span><br><span class="line"></span><br><span class="line">    <span class="comment">// acceptor</span></span><br><span class="line">    <span class="keyword">private</span> IoAcceptor acceptor;</span><br><span class="line">	</span><br><span class="line">    <span class="comment">// workerpool</span></span><br><span class="line">    <span class="keyword">private</span> ExecutorService defaultWorkerPool;</span><br><span class="line">    <span class="keyword">private</span> Executor workerpool;</span><br><span class="line">    </span><br><span class="line">    <span class="comment">//connection manager</span></span><br><span class="line">    <span class="keyword">private</span> ConnectionManager connectionManager = <span class="keyword">new</span> ConnectionManager();</span><br><span class="line">    <span class="keyword">private</span> <span class="keyword">int</span> maxConcurrentConnections = Integer.MAX_VALUE;</span><br><span class="line">    <span class="keyword">private</span> <span class="keyword">boolean</span> isMaxConnectionCheckAvtive = <span class="keyword">false</span>;</span><br><span class="line"></span><br><span class="line">    <span class="comment">// app handler</span></span><br><span class="line">    <span class="keyword">private</span> HandlerAdapter handlerAdapter = HandlerAdapter.newInstance(<span class="keyword">null</span>);</span><br><span class="line">	</span><br><span class="line">    <span class="comment">// timeouts</span></span><br><span class="line">    <span class="keyword">private</span> <span class="keyword">long</span> idleTimeoutMillis = IConnection.MAX_TIMEOUT_MILLIS;</span><br><span class="line">    <span class="keyword">private</span> <span class="keyword">long</span> connectionTimeoutMillis = IConnection.MAX_TIMEOUT_MILLIS;</span><br><span class="line"></span><br><span class="line">    <span class="comment">/**</span><br><span class="line">     * constructor </span><br><span class="line">     * </span><br><span class="line">     * <span class="doctag">@param</span> address              local address</span><br><span class="line">     * <span class="doctag">@param</span> options              the socket options</span><br><span class="line">     * <span class="doctag">@param</span> handler              the handler to use (supported: IConnectHandler, IDisconnectHandler, IDataHandler, IIdleTimeoutHandler, IConnectionTimeoutHandler, IConnectionScoped, ILifeCycle)</span><br><span class="line">     * <span class="doctag">@param</span> sslOn                true, is SSL should be activated</span><br><span class="line">     * <span class="doctag">@param</span> sslContext           the ssl context to use</span><br><span class="line">     * <span class="doctag">@param</span> backlog              The maximum number number of pending connections. If has the value 0, or a negative value, then an implementation specific default is used.</span><br><span class="line">     * <span class="doctag">@param</span> minPoolsize          The min workerpool size</span><br><span class="line">     * <span class="doctag">@param</span> maxPoolsize          The max workerpool size</span><br><span class="line">     * <span class="doctag">@param</span> taskqueueSize        The taskqueue size</span><br><span class="line">     * <span class="doctag">@throws</span> UnknownHostException if the local host cannot determined</span><br><span class="line">     * <span class="doctag">@throws</span> IOException If some other I/O error occurs</span><br><span class="line">     */</span></span><br><span class="line">    <span class="function"><span class="keyword">protected</span> <span class="title">Server</span><span class="params">(InetSocketAddress address, Map&lt;String, Object&gt; options, IHandler handler, SSLContext sslContext, <span class="keyword">boolean</span> sslOn, <span class="keyword">int</span> backlog, <span class="keyword">int</span> minPoolsize, <span class="keyword">int</span> maxPoolsize, <span class="keyword">int</span> taskqueueSize)</span> <span class="keyword">throws</span> UnknownHostException, IOException </span>&#123;</span><br><span class="line">        defaultWorkerPool = <span class="keyword">new</span> WorkerPool(minPoolsize, maxPoolsize, taskqueueSize);</span><br><span class="line">        workerpool = defaultWorkerPool;</span><br><span class="line">        <span class="keyword">if</span> (sslContext != <span class="keyword">null</span>) &#123;</span><br><span class="line">            acceptor = ConnectionUtils.getIoProvider().createAcceptor(<span class="keyword">new</span> LifeCycleHandler(), address, backlog, options, sslContext, sslOn);</span><br><span class="line">        &#125; <span class="keyword">else</span> &#123;</span><br><span class="line">            acceptor = ConnectionUtils.getIoProvider().createAcceptor(<span class="keyword">new</span> LifeCycleHandler(), address, backlog, options);</span><br><span class="line">        &#125;</span><br><span class="line">		</span><br><span class="line">        setHandler(handler);</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="function"><span class="keyword">public</span> <span class="keyword">void</span> <span class="title">setHandler</span><span class="params">(IHandler handler)</span> </span>&#123;</span><br><span class="line">        handlerAdapter = HandlerAdapter.newInstance(handler);</span><br><span class="line">        initCurrentHandler();</span><br><span class="line">    &#125;</span><br><span class="line">    </span><br><span class="line">    <span class="function"><span class="keyword">private</span> <span class="keyword">void</span> <span class="title">initCurrentHandler</span><span class="params">()</span> </span>&#123;</span><br><span class="line">        ConnectionUtils.injectServerField(<span class="keyword">this</span>, handlerAdapter.getHandler());</span><br><span class="line">        handlerAdapter.onInit();</span><br><span class="line">    &#125;</span><br><span class="line">	</span><br><span class="line">    <span class="function"><span class="keyword">private</span> <span class="keyword">void</span> <span class="title">callCurrentHandlerOnDestroy</span><span class="params">()</span> </span>&#123;</span><br><span class="line">        handlerAdapter.onDestroy();</span><br><span class="line">    &#125;</span><br><span class="line">    </span><br><span class="line">    <span class="function"><span class="keyword">public</span> <span class="keyword">void</span> <span class="title">run</span><span class="params">()</span> </span>&#123;</span><br><span class="line">        startUpTime = System.currentTimeMillis();</span><br><span class="line">        acceptor.listen();</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="function"><span class="keyword">public</span> <span class="keyword">void</span> <span class="title">start</span><span class="params">()</span> <span class="keyword">throws</span> IOException </span>&#123;</span><br><span class="line">        ConnectionUtils.start(<span class="keyword">this</span>);</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="function"><span class="keyword">public</span> <span class="keyword">final</span> <span class="keyword">void</span> <span class="title">close</span><span class="params">()</span> </span>&#123;</span><br><span class="line">        <span class="comment">//资源销毁</span></span><br><span class="line">    &#125;</span><br><span class="line">    <span class="comment">//如果我们定义了WorkerPool，则会启动WorkerpoolCloser服务负责销毁WorkerPool</span></span><br><span class="line">    <span class="keyword">private</span> <span class="keyword">static</span> <span class="keyword">final</span> <span class="class"><span class="keyword">class</span> <span class="title">WorkerpoolCloser</span> <span class="keyword">extends</span> <span class="title">Thread</span> </span>&#123;</span><br><span class="line">        <span class="comment">//......</span></span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure></p>
<p>　　可以看到，在其构造方法中，我们初始化了WorkerPool、IoAcceptor和IHandler等关键类，后面我们再详细介绍。在其start方法中，我们调用了org.xsocket.connection.ConnectionUtils 的 start 方法新起了一个线程，该线程的run实现方法为Server的run方法。Server的run方法调用了IoAcceptor的listen方法。</p>
<h2 id="WorkerPool"><a href="#WorkerPool" class="headerlink" title="WorkerPool"></a>WorkerPool</h2><p>　　首先我们看看WorkerPool线程池的核心代码<br><figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br><span class="line">50</span><br><span class="line">51</span><br><span class="line">52</span><br><span class="line">53</span><br><span class="line">54</span><br><span class="line">55</span><br><span class="line">56</span><br><span class="line">57</span><br><span class="line">58</span><br><span class="line">59</span><br><span class="line">60</span><br><span class="line">61</span><br><span class="line">62</span><br><span class="line">63</span><br><span class="line">64</span><br><span class="line">65</span><br><span class="line">66</span><br><span class="line">67</span><br><span class="line">68</span><br><span class="line">69</span><br><span class="line">70</span><br><span class="line">71</span><br><span class="line">72</span><br><span class="line">73</span><br><span class="line">74</span><br><span class="line">75</span><br><span class="line">76</span><br><span class="line">77</span><br><span class="line">78</span><br><span class="line">79</span><br><span class="line">80</span><br><span class="line">81</span><br><span class="line">82</span><br><span class="line">83</span><br><span class="line">84</span><br><span class="line">85</span><br><span class="line">86</span><br><span class="line">87</span><br><span class="line">88</span><br><span class="line">89</span><br><span class="line">90</span><br><span class="line">91</span><br><span class="line">92</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">public</span> <span class="keyword">final</span> <span class="class"><span class="keyword">class</span> <span class="title">WorkerPool</span> <span class="keyword">extends</span> <span class="title">ThreadPoolExecutor</span> </span>&#123;</span><br><span class="line">    <span class="comment">//其他的构造方法</span></span><br><span class="line">	</span><br><span class="line">    <span class="comment">/**</span><br><span class="line">     * constructor </span><br><span class="line">     * </span><br><span class="line">     * <span class="doctag">@param</span> minSize       min worker size</span><br><span class="line">     * <span class="doctag">@param</span> maxSize       max worker size</span><br><span class="line">     * <span class="doctag">@param</span> keepalive     the keepalive</span><br><span class="line">     * <span class="doctag">@param</span> timeunit      the timeunit</span><br><span class="line">     * <span class="doctag">@param</span> taskqueuesize the task queue size </span><br><span class="line">     * <span class="doctag">@param</span> isDaemon  true, if worker threads are daemon threads</span><br><span class="line">     */</span></span><br><span class="line">    <span class="function"><span class="keyword">public</span> <span class="title">WorkerPool</span><span class="params">(<span class="keyword">int</span> minSize, <span class="keyword">int</span> maxSize, <span class="keyword">long</span> keepalive, TimeUnit timeunit, <span class="keyword">int</span> taskqueuesize, <span class="keyword">boolean</span> isDaemon)</span> </span>&#123;</span><br><span class="line">        <span class="keyword">super</span>(minSize, maxSize, keepalive, timeunit, <span class="keyword">new</span> WorkerPoolAwareQueue(taskqueuesize), <span class="keyword">new</span> DefaultThreadFactory(isDaemon));</span><br><span class="line">        <span class="comment">//调用父类的getQueue方法，强转为WorkerPoolAwareQueue</span></span><br><span class="line">        ((WorkerPoolAwareQueue) getQueue()).init(<span class="keyword">this</span>);</span><br><span class="line">    &#125;</span><br><span class="line">    </span><br><span class="line">    <span class="keyword">private</span> <span class="keyword">static</span> <span class="keyword">final</span> <span class="class"><span class="keyword">class</span> <span class="title">WorkerPoolAwareQueue</span> <span class="keyword">extends</span> <span class="title">LinkedBlockingQueue</span>&lt;<span class="title">Runnable</span>&gt; </span>&#123;</span><br><span class="line">        </span><br><span class="line">        <span class="keyword">private</span> WorkerPool workerPool;</span><br><span class="line">        </span><br><span class="line">        <span class="function"><span class="keyword">public</span> <span class="title">WorkerPoolAwareQueue</span><span class="params">(<span class="keyword">int</span> capacity)</span> </span>&#123;</span><br><span class="line">            <span class="keyword">super</span>(capacity);</span><br><span class="line">        &#125;</span><br><span class="line">        </span><br><span class="line">        <span class="function"><span class="keyword">public</span> <span class="keyword">void</span> <span class="title">init</span><span class="params">(WorkerPool workerPool)</span> </span>&#123;</span><br><span class="line">            <span class="keyword">this</span>.workerPool = workerPool;</span><br><span class="line">        &#125;</span><br><span class="line">        <span class="comment">//向queue中插入数据</span></span><br><span class="line">        <span class="function"><span class="keyword">public</span> <span class="keyword">boolean</span> <span class="title">offer</span><span class="params">(Runnable task)</span> </span>&#123;</span><br><span class="line"></span><br><span class="line">            <span class="comment">// 线程池中正在活动（执行）的线程数比池中的线程数要小</span></span><br><span class="line">            <span class="keyword">if</span> (workerPool.getActiveCount() &lt; workerPool.getPoolSize()) &#123;</span><br><span class="line">				<span class="comment">//有空闲的线程可用，立即执行</span></span><br><span class="line">                <span class="comment">// </span></span><br><span class="line">                <span class="keyword">return</span> <span class="keyword">super</span>.offer(task);</span><br><span class="line">            &#125;</span><br><span class="line">			<span class="comment">//上一步的判断后，运行到此处则说明：</span></span><br><span class="line">            <span class="comment">//此时线程池中的线程（全部为活动的）数超过了线程池的最大值</span></span><br><span class="line">            <span class="keyword">if</span> (workerPool.getPoolSize() &gt;= workerPool.getMaximumPoolSize()) &#123;</span><br><span class="line">                <span class="comment">// 将task添加到queue尾部，等待一个可用的线程处理该task</span></span><br><span class="line">                <span class="keyword">if</span> (LOG.isLoggable(Level.FINE)) &#123;</span><br><span class="line">                    LOG.fine(<span class="string">"add task to queue waiting for the next free one"</span>);</span><br><span class="line">                &#125;</span><br><span class="line">                <span class="keyword">return</span> <span class="keyword">super</span>.offer(task);</span><br><span class="line">            &#125; <span class="keyword">else</span> &#123;</span><br><span class="line">                <span class="comment">// return false, which forces starting a new thread. The new</span></span><br><span class="line">                <span class="comment">// thread performs the task and will be added to workerpool</span></span><br><span class="line">                <span class="comment">// after performing the task </span></span><br><span class="line">                <span class="comment">// As result the workerpool is increased. If the thread reach</span></span><br><span class="line">                <span class="comment">// its keepalive timeout (waiting for new tasks), the thread </span></span><br><span class="line">                <span class="comment">// will terminate itself</span></span><br><span class="line">                </span><br><span class="line">                <span class="keyword">if</span> (LOG.isLoggable(Level.FINE)) &#123;</span><br><span class="line">                    LOG.fine(<span class="string">"initiate creating a new thread"</span>);</span><br><span class="line">                &#125;</span><br><span class="line">                <span class="keyword">return</span> <span class="keyword">false</span>;</span><br><span class="line">            &#125;</span><br><span class="line">        &#125;</span><br><span class="line">    &#125;</span><br><span class="line">    </span><br><span class="line">    </span><br><span class="line">    <span class="keyword">private</span> <span class="keyword">static</span> <span class="class"><span class="keyword">class</span> <span class="title">DefaultThreadFactory</span> <span class="keyword">implements</span> <span class="title">ThreadFactory</span> </span>&#123;</span><br><span class="line">        </span><br><span class="line">        <span class="keyword">private</span> <span class="keyword">static</span> <span class="keyword">final</span> AtomicInteger poolNumber = <span class="keyword">new</span> AtomicInteger(<span class="number">1</span>);</span><br><span class="line">        </span><br><span class="line">        <span class="keyword">private</span> <span class="keyword">final</span> AtomicInteger threadNumber = <span class="keyword">new</span> AtomicInteger(<span class="number">1</span>);</span><br><span class="line">        <span class="keyword">private</span> <span class="keyword">final</span> String namePrefix;</span><br><span class="line">        <span class="keyword">private</span> <span class="keyword">final</span> <span class="keyword">boolean</span> isDaemon;</span><br><span class="line"></span><br><span class="line">        DefaultThreadFactory(<span class="keyword">boolean</span> isDaemon) &#123;</span><br><span class="line">            <span class="keyword">this</span>.isDaemon = isDaemon;</span><br><span class="line">            namePrefix = <span class="string">"xWorkerPool-"</span> + poolNumber.getAndIncrement() + <span class="string">"-thread-"</span>;</span><br><span class="line">        &#125;</span><br><span class="line"></span><br><span class="line">        <span class="function"><span class="keyword">public</span> Thread <span class="title">newThread</span><span class="params">(Runnable r)</span> </span>&#123;</span><br><span class="line">            <span class="keyword">if</span> (LOG.isLoggable(Level.FINE)) &#123;</span><br><span class="line">                LOG.fine(<span class="string">"creating new thread"</span>);</span><br><span class="line">            &#125;</span><br><span class="line">            </span><br><span class="line">            Thread t = <span class="keyword">new</span> Thread(r, namePrefix + threadNumber.getAndIncrement());</span><br><span class="line">            t.setDaemon(isDaemon);</span><br><span class="line"></span><br><span class="line">            <span class="keyword">if</span> (t.getPriority() != Thread.NORM_PRIORITY) &#123;</span><br><span class="line">                t.setPriority(Thread.NORM_PRIORITY);</span><br><span class="line">            &#125;</span><br><span class="line">            <span class="keyword">return</span> t;</span><br><span class="line">        &#125;</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure></p>
<p>下面我们看看IoAcceptor的源码，并重点关注其 listen 方法。</p>
<h2 id="IoAcceptor"><a href="#IoAcceptor" class="headerlink" title="IoAcceptor"></a>IoAcceptor</h2><p>　　在xSocket中，IoAcceptor主要负责处理客户端的连接，下面为其关键代码：<br><figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">final</span> <span class="class"><span class="keyword">class</span> <span class="title">IoAcceptor</span>  </span>&#123;</span><br><span class="line">    <span class="keyword">private</span> IIoAcceptorCallback callback;</span><br><span class="line">    <span class="keyword">private</span> <span class="keyword">final</span> ServerSocketChannel serverChannel;</span><br><span class="line">    <span class="keyword">private</span> <span class="keyword">final</span> IoSocketDispatcherPool dispatcherPool;</span><br><span class="line"></span><br><span class="line">    <span class="function"><span class="keyword">public</span> <span class="title">IoAcceptor</span><span class="params">(IIoAcceptorCallback callback, InetSocketAddress address, <span class="keyword">int</span> backlog, SSLContext sslContext, <span class="keyword">boolean</span> sslOn, <span class="keyword">boolean</span> isReuseAddress)</span> <span class="keyword">throws</span> IOException </span>&#123;</span><br><span class="line">        <span class="keyword">this</span>.callback = callback;</span><br><span class="line"></span><br><span class="line">        serverChannel = ServerSocketChannel.open();</span><br><span class="line">        <span class="keyword">assert</span> (serverChannel != <span class="keyword">null</span>);</span><br><span class="line">        </span><br><span class="line">        serverChannel.configureBlocking(<span class="keyword">true</span>);</span><br><span class="line">        serverChannel.socket().setSoTimeout(<span class="number">0</span>);  <span class="comment">// accept method never times out</span></span><br><span class="line">        serverChannel.socket().setReuseAddress(isReuseAddress); </span><br><span class="line">        </span><br><span class="line">        <span class="keyword">try</span> &#123;</span><br><span class="line">            serverChannel.socket().bind(address, backlog);</span><br><span class="line">            dispatcherPool = <span class="keyword">new</span> IoSocketDispatcherPool(<span class="string">"Srv"</span> + getLocalPort(), IoProvider.getServerDispatcherInitialSize());</span><br><span class="line">        &#125; <span class="keyword">catch</span> (BindException be) &#123;</span><br><span class="line">        	serverChannel.close();</span><br><span class="line">        &#125;</span><br><span class="line">    &#125;</span><br><span class="line">    </span><br><span class="line">    <span class="function"><span class="keyword">public</span> <span class="keyword">void</span> <span class="title">listen</span><span class="params">()</span> <span class="keyword">throws</span> IOException </span>&#123;</span><br><span class="line">    	callback.onConnected();</span><br><span class="line">    	accept();</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="function"><span class="keyword">private</span> <span class="keyword">void</span> <span class="title">accept</span><span class="params">()</span> </span>&#123;</span><br><span class="line">        <span class="keyword">while</span> (isOpen.get()) &#123;</span><br><span class="line">            <span class="keyword">try</span> &#123;</span><br><span class="line">                <span class="comment">// blocking accept call</span></span><br><span class="line">                SocketChannel channel = serverChannel.accept();</span><br><span class="line"></span><br><span class="line">                <span class="comment">//新的客户端连接，获取一个IoSocketDispatcher</span></span><br><span class="line">                IoSocketDispatcher dispatcher = dispatcherPool.nextDispatcher();</span><br><span class="line">                <span class="comment">//同时创建一个链式处理器</span></span><br><span class="line">                IoChainableHandler ioHandler = ConnectionUtils.getIoProvider().createIoHandler(<span class="keyword">false</span>, dispatcher, channel, sslContext, sslOn);</span><br><span class="line">                <span class="comment">//callback对象为Server的内部类LifeCycleHandler</span></span><br><span class="line">                callback.onConnectionAccepted(ioHandler);</span><br><span class="line">				<span class="comment">//连接数+1</span></span><br><span class="line">                acceptedConnections++;</span><br><span class="line">            &#125; <span class="keyword">catch</span> (Exception e) &#123;&#125;</span><br><span class="line">        &#125;</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure></p>
<p>　　在IoAcceptor的构造方法中，我们打开了ServerSocketChannel，并新建了一个IoSocketDispatcherPool对象。accept方法则主要负责处理客户端的连接，每当有新的连接建立时，就会从IoSocketDispatcherPool中获取一个IoSocketDispatcher并生成一个IoChainableHandler，IoChainableHandler包含了SocketChannel、IoSocketDispatcher等信息。最后执行callback的onConnectionAccepted方法，这里的callback实际上为LifeCycleHandler类的一个实例。</p>
<h2 id="IoSocketDispatcher"><a href="#IoSocketDispatcher" class="headerlink" title="IoSocketDispatcher"></a>IoSocketDispatcher</h2><p>　　在介绍IoSocketDispatcher之前，我们先简单说一下IoSocketDispatcherPool。顾名思义，IoSocketDispatcherPool就是一个容纳IoSocketDispatcher的池。在IOAcceptor初始化时，同时初始化该池的大小为2，并初始化相应数量（这里为2）的IoSocketDispatcher。注意，每次初始化IoSocketDispatcher（Runnable类型）后，都会启动它，我们看看其初始化启动的关键代码：<br><figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br></pre></td><td class="code"><pre><span class="line"><span class="function"><span class="keyword">private</span> <span class="keyword">synchronized</span> <span class="keyword">void</span> <span class="title">updateDispatcher</span><span class="params">()</span> </span>&#123;</span><br><span class="line">    <span class="keyword">for</span> (<span class="keyword">int</span> i = <span class="number">0</span>; i &lt; size; i++) &#123;</span><br><span class="line">        IoUnsynchronizedMemoryManager memoryManager = <span class="keyword">null</span>;</span><br><span class="line">        <span class="keyword">if</span> (preallocation) &#123;</span><br><span class="line">            memoryManager = IoUnsynchronizedMemoryManager.createPreallocatedMemoryManager(preallocationSize, bufferMinsize, useDirect);</span><br><span class="line">        &#125; <span class="keyword">else</span> &#123;</span><br><span class="line">            memoryManager = IoUnsynchronizedMemoryManager.createNonPreallocatedMemoryManager(useDirect);</span><br><span class="line">        &#125;</span><br><span class="line">		</span><br><span class="line">        IoSocketDispatcher dispatcher = <span class="keyword">new</span> IoSocketDispatcher(memoryManager, name + <span class="string">"#"</span> + i);</span><br><span class="line">        dispatchers.addLast(dispatcher);</span><br><span class="line"></span><br><span class="line">        Thread t = <span class="keyword">new</span> Thread(dispatcher);</span><br><span class="line">        t.setDaemon(<span class="keyword">true</span>);</span><br><span class="line">        t.start();</span><br><span class="line"></span><br><span class="line">        <span class="keyword">for</span> (IIoDispatcherPoolListener listener : listeners) &#123;</span><br><span class="line">            listener.onDispatcherAdded(dispatcher);</span><br><span class="line">        &#125;</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure></p>
<p>　　每当有新的连接到来时，根据round-robin算法从上面的IoSocketDispatcherPool池中选择一个IoSocketDispatcher，用来处理该连接。下面我们看看IoSocketDispatcher的关键代码，如run、handleReadWriteKeys、onReadableEvent、onWriteableEvent和register等方法!<br><figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br><span class="line">50</span><br><span class="line">51</span><br><span class="line">52</span><br><span class="line">53</span><br><span class="line">54</span><br><span class="line">55</span><br><span class="line">56</span><br><span class="line">57</span><br><span class="line">58</span><br><span class="line">59</span><br><span class="line">60</span><br><span class="line">61</span><br><span class="line">62</span><br><span class="line">63</span><br><span class="line">64</span><br><span class="line">65</span><br><span class="line">66</span><br><span class="line">67</span><br><span class="line">68</span><br><span class="line">69</span><br><span class="line">70</span><br><span class="line">71</span><br><span class="line">72</span><br><span class="line">73</span><br><span class="line">74</span><br><span class="line">75</span><br><span class="line">76</span><br><span class="line">77</span><br><span class="line">78</span><br><span class="line">79</span><br><span class="line">80</span><br><span class="line">81</span><br><span class="line">82</span><br><span class="line">83</span><br><span class="line">84</span><br><span class="line">85</span><br><span class="line">86</span><br><span class="line">87</span><br><span class="line">88</span><br><span class="line">89</span><br><span class="line">90</span><br><span class="line">91</span><br><span class="line">92</span><br><span class="line">93</span><br><span class="line">94</span><br><span class="line">95</span><br><span class="line">96</span><br><span class="line">97</span><br><span class="line">98</span><br><span class="line">99</span><br><span class="line">100</span><br><span class="line">101</span><br><span class="line">102</span><br><span class="line">103</span><br><span class="line">104</span><br><span class="line">105</span><br><span class="line">106</span><br><span class="line">107</span><br><span class="line">108</span><br><span class="line">109</span><br><span class="line">110</span><br><span class="line">111</span><br><span class="line">112</span><br><span class="line">113</span><br><span class="line">114</span><br><span class="line">115</span><br><span class="line">116</span><br><span class="line">117</span><br><span class="line">118</span><br><span class="line">119</span><br><span class="line">120</span><br><span class="line">121</span><br><span class="line">122</span><br><span class="line">123</span><br><span class="line">124</span><br><span class="line">125</span><br><span class="line">126</span><br><span class="line">127</span><br><span class="line">128</span><br><span class="line">129</span><br><span class="line">130</span><br><span class="line">131</span><br><span class="line">132</span><br><span class="line">133</span><br><span class="line">134</span><br><span class="line">135</span><br><span class="line">136</span><br><span class="line">137</span><br><span class="line">138</span><br><span class="line">139</span><br><span class="line">140</span><br><span class="line">141</span><br><span class="line">142</span><br><span class="line">143</span><br><span class="line">144</span><br><span class="line">145</span><br><span class="line">146</span><br><span class="line">147</span><br><span class="line">148</span><br><span class="line">149</span><br><span class="line">150</span><br><span class="line">151</span><br><span class="line">152</span><br><span class="line">153</span><br><span class="line">154</span><br><span class="line">155</span><br><span class="line">156</span><br><span class="line">157</span><br><span class="line">158</span><br><span class="line">159</span><br><span class="line">160</span><br><span class="line">161</span><br><span class="line">162</span><br><span class="line">163</span><br><span class="line">164</span><br><span class="line">165</span><br><span class="line">166</span><br><span class="line">167</span><br><span class="line">168</span><br><span class="line">169</span><br><span class="line">170</span><br><span class="line">171</span><br><span class="line">172</span><br><span class="line">173</span><br><span class="line">174</span><br><span class="line">175</span><br><span class="line">176</span><br><span class="line">177</span><br><span class="line">178</span><br><span class="line">179</span><br><span class="line">180</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">final</span> <span class="class"><span class="keyword">class</span> <span class="title">IoSocketDispatcher</span> <span class="keyword">extends</span> <span class="title">MonitoredSelector</span> <span class="keyword">implements</span> <span class="title">Runnable</span>, <span class="title">Closeable</span> </span>&#123;</span><br><span class="line">	<span class="comment">// queues</span></span><br><span class="line">    <span class="keyword">private</span> <span class="keyword">final</span> ConcurrentLinkedQueue&lt;Runnable&gt; registerQueue = <span class="keyword">new</span> ConcurrentLinkedQueue&lt;Runnable&gt;();</span><br><span class="line">    <span class="keyword">private</span> <span class="keyword">final</span> ConcurrentLinkedQueue&lt;IoSocketHandler&gt; deregisterQueue = <span class="keyword">new</span> ConcurrentLinkedQueue&lt;IoSocketHandler&gt;();</span><br><span class="line"></span><br><span class="line">    <span class="keyword">private</span> Selector selector;</span><br><span class="line"></span><br><span class="line">    <span class="function"><span class="keyword">public</span> <span class="title">IoSocketDispatcher</span><span class="params">(AbstractMemoryManager memoryManager, String name)</span>  </span>&#123;</span><br><span class="line">        <span class="keyword">this</span>.memoryManager = memoryManager;</span><br><span class="line">        <span class="comment">//省略其他代码</span></span><br><span class="line">        <span class="keyword">try</span> &#123;</span><br><span class="line">            selector = Selector.open();</span><br><span class="line">        &#125; <span class="keyword">catch</span> (IOException ioe) &#123;&#125;</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="function"><span class="keyword">void</span> <span class="title">reinit</span><span class="params">()</span> <span class="keyword">throws</span> IOException </span>&#123;</span><br><span class="line">        <span class="comment">//重新open一个Selector，并替换之前的</span></span><br><span class="line">    &#125;</span><br><span class="line">	</span><br><span class="line">    <span class="function"><span class="keyword">public</span> <span class="keyword">void</span> <span class="title">run</span><span class="params">()</span> </span>&#123;</span><br><span class="line">        Thread.currentThread().setName(name);</span><br><span class="line">        <span class="keyword">while</span>(isOpen.get()) &#123;</span><br><span class="line">            <span class="keyword">try</span> &#123;</span><br><span class="line">                <span class="keyword">int</span> eventCount = selector.select(<span class="number">5000</span>); </span><br><span class="line">                <span class="keyword">if</span> (eventCount &gt; <span class="number">0</span>) &#123;</span><br><span class="line">                    handleReadWriteKeys();</span><br><span class="line">                &#125;</span><br><span class="line">            &#125; <span class="keyword">catch</span> (Throwable e) &#123;&#125;</span><br><span class="line">        &#125;</span><br><span class="line">        <span class="comment">//循环结束，处理关闭</span></span><br><span class="line">        <span class="keyword">for</span> (IoSocketHandler socketHandler : getRegistered()) &#123;</span><br><span class="line">            socketHandler.onDeregisteredEvent();</span><br><span class="line">        &#125;</span><br><span class="line">        </span><br><span class="line">        <span class="keyword">try</span> &#123;</span><br><span class="line">            selector.close();</span><br><span class="line">        &#125; <span class="keyword">catch</span> (Exception e) &#123;&#125;</span><br><span class="line">    &#125;</span><br><span class="line">    <span class="comment">//处理读写时间</span></span><br><span class="line">    <span class="function"><span class="keyword">private</span> <span class="keyword">void</span> <span class="title">handleReadWriteKeys</span><span class="params">()</span> </span>&#123;</span><br><span class="line">        Set&lt;SelectionKey&gt; selectedEventKeys = selector.selectedKeys();</span><br><span class="line">        Iterator&lt;SelectionKey&gt; it = selectedEventKeys.iterator();</span><br><span class="line">        <span class="comment">// handle read &amp; write</span></span><br><span class="line">        <span class="keyword">while</span> (it.hasNext()) &#123;</span><br><span class="line">            <span class="keyword">try</span> &#123;</span><br><span class="line">                SelectionKey eventKey = it.next();</span><br><span class="line">                it.remove();</span><br><span class="line">                </span><br><span class="line">                IoSocketHandler socketHandler = (IoSocketHandler) eventKey.attachment();</span><br><span class="line">   </span><br><span class="line">                <span class="keyword">try</span> &#123;</span><br><span class="line">                    <span class="comment">// 读事件</span></span><br><span class="line">                    <span class="keyword">if</span> (eventKey.isValid() &amp;&amp; eventKey.isReadable()) &#123;</span><br><span class="line">                        onReadableEvent(socketHandler);</span><br><span class="line">                    &#125;</span><br><span class="line">                    <span class="comment">// 写事件</span></span><br><span class="line">                    <span class="keyword">if</span> (eventKey.isValid() &amp;&amp; eventKey.isWritable()) &#123;</span><br><span class="line">                        onWriteableEvent(socketHandler);</span><br><span class="line">                    &#125;</span><br><span class="line">                &#125; <span class="keyword">catch</span> (Exception e) &#123;&#125;</span><br><span class="line">            &#125; <span class="keyword">catch</span> (Exception e) &#123;&#125;</span><br><span class="line">        &#125;</span><br><span class="line">	&#125;</span><br><span class="line">    <span class="comment">//处理读取事件</span></span><br><span class="line">    <span class="function"><span class="keyword">private</span> <span class="keyword">void</span> <span class="title">onReadableEvent</span><span class="params">(IoSocketHandler socketHandler)</span> </span>&#123;</span><br><span class="line">        <span class="keyword">try</span> &#123;</span><br><span class="line">            <span class="keyword">long</span> read = socketHandler.onReadableEvent();</span><br><span class="line">            receivedBytes += read;</span><br><span class="line">            handledReads++;</span><br><span class="line">        &#125; <span class="keyword">catch</span> (Exception t) &#123;&#125;</span><br><span class="line">    &#125;</span><br><span class="line">    <span class="comment">//处理io写事件</span></span><br><span class="line">    <span class="function"><span class="keyword">private</span> <span class="keyword">void</span> <span class="title">onWriteableEvent</span><span class="params">(IoSocketHandler socketHandler)</span> </span>&#123;</span><br><span class="line">        <span class="keyword">try</span> &#123;</span><br><span class="line">            socketHandler.onWriteableEvent();</span><br><span class="line">            handledWrites++;</span><br><span class="line">        &#125; <span class="keyword">catch</span> (Exception e) &#123;&#125;</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="function"><span class="keyword">public</span> <span class="keyword">boolean</span> <span class="title">register</span><span class="params">(IoSocketHandler socketHandler, <span class="keyword">int</span> ops)</span> <span class="keyword">throws</span> IOException </span>&#123;</span><br><span class="line">        socketHandler.setMemoryManager(memoryManager);</span><br><span class="line"></span><br><span class="line">        <span class="keyword">if</span> (isDispatcherInstanceThread()) &#123;</span><br><span class="line">            registerHandlerNow(socketHandler, ops);</span><br><span class="line">        &#125; <span class="keyword">else</span> &#123;</span><br><span class="line">            registerQueue.add(<span class="keyword">new</span> RegisterTask(socketHandler, ops));</span><br><span class="line">            wakeUp();</span><br><span class="line">        &#125;</span><br><span class="line">        <span class="keyword">return</span> <span class="keyword">true</span>;</span><br><span class="line">    &#125;</span><br><span class="line">	</span><br><span class="line">    <span class="keyword">private</span> <span class="keyword">final</span> <span class="class"><span class="keyword">class</span> <span class="title">RegisterTask</span> <span class="keyword">implements</span> <span class="title">Runnable</span> </span>&#123;</span><br><span class="line"></span><br><span class="line">        <span class="keyword">private</span> <span class="keyword">final</span> IoSocketHandler socketHandler;</span><br><span class="line">        <span class="keyword">private</span> <span class="keyword">final</span> <span class="keyword">int</span> ops;</span><br><span class="line">				</span><br><span class="line">        <span class="function"><span class="keyword">public</span> <span class="title">RegisterTask</span><span class="params">(IoSocketHandler socketHandler, <span class="keyword">int</span> ops)</span> </span>&#123;</span><br><span class="line">            <span class="keyword">this</span>.socketHandler = socketHandler;</span><br><span class="line">            <span class="keyword">this</span>.ops = ops;</span><br><span class="line">        &#125;</span><br><span class="line">        <span class="function"><span class="keyword">public</span> <span class="keyword">void</span> <span class="title">run</span><span class="params">()</span> </span>&#123;</span><br><span class="line">            <span class="keyword">try</span> &#123;</span><br><span class="line">                registerHandlerNow(socketHandler, ops);</span><br><span class="line">            &#125; <span class="keyword">catch</span> (IOException ioe) &#123;&#125;</span><br><span class="line">        &#125;</span><br><span class="line">    &#125;</span><br><span class="line">	</span><br><span class="line">    <span class="function"><span class="keyword">public</span> <span class="keyword">boolean</span> <span class="title">setWriteSelectionKeyNow</span><span class="params">(<span class="keyword">final</span> IoSocketHandler socketHandler)</span> <span class="keyword">throws</span> IOException </span>&#123;</span><br><span class="line">        SelectionKey key = getSelectionKey(socketHandler);</span><br><span class="line">        <span class="keyword">if</span> (key != <span class="keyword">null</span>) &#123;</span><br><span class="line">            <span class="keyword">if</span> (!isWriteable(key)) &#123;</span><br><span class="line">                key.interestOps(key.interestOps() | SelectionKey.OP_WRITE);</span><br><span class="line">                <span class="keyword">return</span> <span class="keyword">true</span>;</span><br><span class="line">            &#125;</span><br><span class="line">        &#125; <span class="keyword">else</span> &#123;</span><br><span class="line">	    	<span class="keyword">throw</span> <span class="keyword">new</span> IOException(<span class="string">"["</span> + socketHandler.getId() + <span class="string">"] Error occured by setting write selection key. key is null"</span>);</span><br><span class="line">        &#125;</span><br><span class="line">        <span class="keyword">return</span> <span class="keyword">false</span>;</span><br><span class="line">    &#125;</span><br><span class="line">	<span class="comment">//取消指定连接的写兴趣</span></span><br><span class="line">    <span class="function"><span class="keyword">public</span> <span class="keyword">boolean</span> <span class="title">unsetWriteSelectionKeyNow</span><span class="params">(<span class="keyword">final</span> IoSocketHandler socketHandler)</span> <span class="keyword">throws</span> IOException </span>&#123;</span><br><span class="line">        SelectionKey key = getSelectionKey(socketHandler);</span><br><span class="line">        <span class="keyword">if</span> (key != <span class="keyword">null</span>) &#123;</span><br><span class="line">        	<span class="keyword">if</span> (isWriteable(key)) &#123;</span><br><span class="line">                key.interestOps(key.interestOps() &amp; ~SelectionKey.OP_WRITE);   </span><br><span class="line">                <span class="keyword">return</span> <span class="keyword">true</span>;</span><br><span class="line">            &#125;</span><br><span class="line">        &#125; <span class="keyword">else</span> &#123;</span><br><span class="line">            <span class="keyword">throw</span> <span class="keyword">new</span> IOException(<span class="string">"["</span> + socketHandler.getId() + <span class="string">"] Error occured by unsetting write selection key. key is null"</span>);</span><br><span class="line">        &#125;</span><br><span class="line">        <span class="keyword">return</span> <span class="keyword">false</span>;</span><br><span class="line">    &#125;</span><br><span class="line">    <span class="comment">//将socketHandler对应的连接注册到Selector上</span></span><br><span class="line">    <span class="function"><span class="keyword">private</span> <span class="keyword">void</span> <span class="title">registerHandlerNow</span><span class="params">(IoSocketHandler socketHandler, <span class="keyword">int</span> ops)</span> <span class="keyword">throws</span> IOException </span>&#123;</span><br><span class="line">        <span class="keyword">if</span> (socketHandler.isOpen()) &#123;</span><br><span class="line">            <span class="keyword">try</span> &#123;</span><br><span class="line">                socketHandler.getChannel().register(selector, ops, socketHandler);				</span><br><span class="line">                socketHandler.onRegisteredEvent();</span><br><span class="line"></span><br><span class="line">                handledRegistractions++;</span><br><span class="line">            &#125; <span class="keyword">catch</span> (Exception e) &#123;&#125;</span><br><span class="line">        &#125; <span class="keyword">else</span> &#123;</span><br><span class="line">            socketHandler.onRegisteredFailedEvent(<span class="keyword">new</span> IOException(<span class="string">"could not register handler "</span> + socketHandler.getId() + <span class="string">" because the channel is closed"</span>));</span><br><span class="line">        &#125;</span><br><span class="line">    &#125;</span><br><span class="line">    <span class="comment">//每秒数据接收量</span></span><br><span class="line">    <span class="function"><span class="keyword">long</span> <span class="title">getReceiveRateBytesPerSec</span><span class="params">()</span> </span>&#123;</span><br><span class="line">        <span class="keyword">long</span> rate = <span class="number">0</span>;</span><br><span class="line">        <span class="keyword">long</span> elapsed = System.currentTimeMillis() - lastRequestReceiveRate;</span><br><span class="line">        <span class="keyword">if</span> (receivedBytes == <span class="number">0</span>) &#123;</span><br><span class="line">            rate = <span class="number">0</span>;</span><br><span class="line">        &#125; <span class="keyword">else</span> <span class="keyword">if</span> (elapsed == <span class="number">0</span>) &#123;</span><br><span class="line">            rate = Long.MAX_VALUE;</span><br><span class="line">        &#125; <span class="keyword">else</span> &#123;</span><br><span class="line">            rate = ((receivedBytes * <span class="number">1000</span>) / elapsed);</span><br><span class="line">        &#125;</span><br><span class="line">        lastRequestReceiveRate = System.currentTimeMillis();</span><br><span class="line">        receivedBytes = <span class="number">0</span>;</span><br><span class="line"></span><br><span class="line">        <span class="keyword">return</span> rate;</span><br><span class="line">    &#125;</span><br><span class="line">    <span class="comment">//每秒数据发送量</span></span><br><span class="line">    <span class="function"><span class="keyword">long</span> <span class="title">getSendRateBytesPerSec</span><span class="params">()</span> </span>&#123;</span><br><span class="line">        <span class="keyword">long</span> rate = <span class="number">0</span>;</span><br><span class="line">        <span class="keyword">long</span> elapsed = System.currentTimeMillis() - lastRequestSendRate;</span><br><span class="line"></span><br><span class="line">        <span class="keyword">if</span> (sentBytes == <span class="number">0</span>) &#123;</span><br><span class="line">            rate = <span class="number">0</span>;</span><br><span class="line">        &#125; <span class="keyword">else</span> <span class="keyword">if</span> (elapsed == <span class="number">0</span>) &#123;</span><br><span class="line">            rate = Long.MAX_VALUE;</span><br><span class="line">        &#125; <span class="keyword">else</span> &#123;</span><br><span class="line">            rate = ((sentBytes * <span class="number">1000</span>) / elapsed);</span><br><span class="line">        &#125;</span><br><span class="line"></span><br><span class="line">        lastRequestSendRate = System.currentTimeMillis();</span><br><span class="line">        sentBytes = <span class="number">0</span>;</span><br><span class="line"></span><br><span class="line">        <span class="keyword">return</span> rate;</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure></p>
<p>　　我们可以看到，每个 IoSocketDispatcher 都会各自打开一个 Selector ，当新的连接建立后，我们选择一个 IoSocketDispatcher ，然后将该链接注册到相应的 Selector 上。在 IoSocketDispatcher 的run方法，中，会通过while循环实时获取连接的读写事件，最后交由相应的 IoSocketHandler 处理。而 IoSocketHandler 则为 IoChainableHandler 的一个子类。</p>
<h2 id="IoChainableHandler"><a href="#IoChainableHandler" class="headerlink" title="IoChainableHandler"></a>IoChainableHandler</h2><p>　　每次有新客户端连接时，都会新建一个IoChainableHandler用于该连接后续事件的处理，即一个IoChainableHandler负责一个连接的事件处理，下面我们看看IoChainableHandler是如何创建的!<br><figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br></pre></td><td class="code"><pre><span class="line"><span class="function">IoChainableHandler <span class="title">createIoHandler</span><span class="params">(<span class="keyword">boolean</span> isClient, IoSocketDispatcher dispatcher, SocketChannel channel, SSLContext sslContext, <span class="keyword">boolean</span> sslOn)</span> <span class="keyword">throws</span> IOException </span>&#123;</span><br><span class="line">    String connectionId = <span class="keyword">null</span>;</span><br><span class="line">    <span class="keyword">if</span> (isClient) &#123;</span><br><span class="line">        connectionId = idPrefix + <span class="string">"C"</span> + Integer.toHexString(nextId.incrementAndGet());</span><br><span class="line">    &#125; <span class="keyword">else</span> &#123;</span><br><span class="line">        connectionId = idPrefix + <span class="string">"S"</span> + Integer.toHexString(nextId.incrementAndGet());</span><br><span class="line">    &#125;</span><br><span class="line">    IoChainableHandler ioHandler = <span class="keyword">new</span> IoSocketHandler(channel, dispatcher, connectionId);</span><br><span class="line"></span><br><span class="line">    <span class="comment">// ssl connection?</span></span><br><span class="line">    <span class="comment">//...</span></span><br><span class="line">    <span class="keyword">return</span> ioHandler;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure></p>
<p>　　我们在 IoSocketDispatcher 里面说到了， IoSocketDispatcher 负责检测socketchannel的读写状态，最后会调用到 IoSocketHandler 的 onReadableEvent 方法<br><figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br></pre></td><td class="code"><pre><span class="line"><span class="function"><span class="keyword">long</span> <span class="title">onReadableEvent</span><span class="params">()</span> <span class="keyword">throws</span> IOException </span>&#123;</span><br><span class="line">    <span class="keyword">long</span> read = <span class="number">0</span>;</span><br><span class="line">    <span class="comment">// read data from socket</span></span><br><span class="line">    ByteBuffer[] received  = readSocket();</span><br><span class="line">    </span><br><span class="line">    <span class="comment">// handle the data</span></span><br><span class="line">    <span class="keyword">if</span> (received != <span class="keyword">null</span>) &#123;</span><br><span class="line">	    <span class="keyword">int</span> size = <span class="number">0</span>;</span><br><span class="line">	    <span class="keyword">for</span> (ByteBuffer byteBuffer : received) &#123;</span><br><span class="line">		    size += byteBuffer.remaining();</span><br><span class="line">	    &#125;</span><br><span class="line">	    read += size;</span><br><span class="line">        <span class="comment">// getPreviousCallback()即返回了之前NonBlockingConnection传的IoHandlerCallback</span></span><br><span class="line">        <span class="comment">// 它是NonBlockingConnection的一个内部类，它的方法直接调用了NonBlockingConnection相应的方法，</span></span><br><span class="line">		<span class="comment">// 这个内部类可以看做只是提供了闭包的作用，甚至可以将NonBlockingConnection直接传给IoSocketHandler的。</span></span><br><span class="line">	    getPreviousCallback().onData(received, size);</span><br><span class="line">	    getPreviousCallback().onPostData();</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="comment">// increase preallocated read memory if not sufficient</span></span><br><span class="line">    checkPreallocatedReadMemory();</span><br><span class="line"></span><br><span class="line">    <span class="keyword">return</span> read;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure></p>
<p>　　onReadableEvent内部将读取到的数据通过 NonBlockingConnection 的 onData 方法回调，然后会将数据加入到NonBlockingConnection的readQueue中。<br>　　之后执行 NonBlockingConnection 的 onPostData ，onPostData内部继续调用 HandlerAdapter 的 onData 方法。下面我们看看 HandlerAdapter 的 onData 方法。<br><figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br></pre></td><td class="code"><pre><span class="line"><span class="function"><span class="keyword">public</span> <span class="keyword">boolean</span> <span class="title">onData</span><span class="params">(INonBlockingConnection connection, SerializedTaskQueue taskQueue, Executor workerpool, <span class="keyword">boolean</span> ignoreException, <span class="keyword">boolean</span> isUnsynchronized)</span> </span>&#123;</span><br><span class="line">    <span class="keyword">if</span> (handlerInfo.isDataHandler()) &#123;</span><br><span class="line">        <span class="keyword">if</span> (handlerInfo.isUnsynchronized()) &#123;</span><br><span class="line">            performOnData(connection, taskQueue, ignoreException, (IDataHandler) handler);</span><br><span class="line">        &#125; <span class="keyword">else</span> &#123;</span><br><span class="line">            <span class="keyword">if</span> (getHandlerInfo().isDataHandlerMultithreaded()) &#123;</span><br><span class="line">                taskQueue.performMultiThreaded(<span class="keyword">new</span> PerformOnDataTask(connection, taskQueue, ignoreException, (IDataHandler) handler), workerpool);</span><br><span class="line">            &#125; <span class="keyword">else</span> &#123;</span><br><span class="line">                <span class="keyword">if</span> (isUnsynchronized) &#123;</span><br><span class="line">                    performOnData(connection, taskQueue, ignoreException, (IDataHandler) handler);</span><br><span class="line">                &#125; <span class="keyword">else</span> &#123;</span><br><span class="line">                    taskQueue.performNonThreaded(<span class="keyword">new</span> PerformOnDataTask(connection, taskQueue, ignoreException, (IDataHandler) handler), workerpool);</span><br><span class="line">                &#125;</span><br><span class="line">            &#125;</span><br><span class="line">        &#125;</span><br><span class="line">    &#125;</span><br><span class="line">    <span class="keyword">return</span> <span class="keyword">true</span>;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure></p>
<p>　　内部执行了 taskQueue 的 performMultiThreaded 方法。这里简单说说SerializedTaskQueue类，它封装了一个Runnable 链表保存任务，一个执行线程执行链表中的任务。<br>　　上面的方法将新创建的 PerFormOnDataTask （HandlerAdapter内部类）加入到了链表，并使用workpool启动了执行线程，这样就执行了PerformOnData的run方法。之前的操作都是在Dispatcher线程中，到此Dispatcher线程重新回到循环中等待新的事件。也就是每次我们的逻辑代码都是用的独立的线程执行的，PerformOnDataTask的run方法调用了HandlerAdapter的performOnData函数。<br><figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br></pre></td><td class="code"><pre><span class="line"><span class="function"><span class="keyword">private</span> <span class="keyword">static</span> <span class="keyword">void</span> <span class="title">performOnData</span><span class="params">(INonBlockingConnection connection, SerializedTaskQueue taskQueue, <span class="keyword">boolean</span> ignoreException, IDataHandler handler)</span> </span>&#123;</span><br><span class="line">    <span class="keyword">try</span> &#123;</span><br><span class="line">		<span class="comment">// loop until readQueue is empty or nor processing has been done (readQueue has not been modified)</span></span><br><span class="line">        <span class="keyword">while</span> ((connection.available() != <span class="number">0</span>) &amp;&amp; !connection.isReceivingSuspended()) &#123;</span><br><span class="line">            <span class="keyword">int</span> version = connection.getReadBufferVersion();</span><br><span class="line">			handler.onData(connection);</span><br><span class="line">        &#125;</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure></p>
<p>　　performOnData方法最终都执行了IDataHandler的onData方法，而它就是我们之前定义的ServerHandler类！</p>
<h2 id="LifeCycleHandler"><a href="#LifeCycleHandler" class="headerlink" title="LifeCycleHandler"></a>LifeCycleHandler</h2><p>　　每次新的连接到来时，由Server的内部类LifeCycleHandler的onConnectionAccepted方法负责该链接的初始化工作，下面我们看看其源码：<br><figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br><span class="line">50</span><br><span class="line">51</span><br><span class="line">52</span><br><span class="line">53</span><br><span class="line">54</span><br><span class="line">55</span><br><span class="line">56</span><br><span class="line">57</span><br><span class="line">58</span><br><span class="line">59</span><br><span class="line">60</span><br><span class="line">61</span><br><span class="line">62</span><br><span class="line">63</span><br><span class="line">64</span><br><span class="line">65</span><br><span class="line">66</span><br><span class="line">67</span><br><span class="line">68</span><br><span class="line">69</span><br><span class="line">70</span><br><span class="line">71</span><br><span class="line">72</span><br><span class="line">73</span><br><span class="line">74</span><br><span class="line">75</span><br><span class="line">76</span><br><span class="line">77</span><br><span class="line">78</span><br><span class="line">79</span><br><span class="line">80</span><br><span class="line">81</span><br><span class="line">82</span><br><span class="line">83</span><br><span class="line">84</span><br><span class="line">85</span><br><span class="line">86</span><br><span class="line">87</span><br><span class="line">88</span><br><span class="line">89</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">private</span> <span class="keyword">final</span> <span class="class"><span class="keyword">class</span> <span class="title">LifeCycleHandler</span> <span class="keyword">implements</span> <span class="title">IIoAcceptorCallback</span> </span>&#123;</span><br><span class="line">    <span class="comment">//服务端启动时执行一次</span></span><br><span class="line">    <span class="function"><span class="keyword">public</span> <span class="keyword">void</span> <span class="title">onConnected</span><span class="params">()</span> </span>&#123;</span><br><span class="line">        isOpen.set(<span class="keyword">true</span>);</span><br><span class="line">        <span class="comment">// notify listeners</span></span><br><span class="line">        <span class="keyword">for</span> (IServerListener listener : (ArrayList&lt;IServerListener&gt;) listeners.clone()) &#123;</span><br><span class="line">            listener.onInit();</span><br><span class="line">        &#125;</span><br><span class="line">    &#125;</span><br><span class="line">	</span><br><span class="line">    <span class="function"><span class="keyword">public</span> <span class="keyword">void</span> <span class="title">onDisconnected</span><span class="params">()</span> </span>&#123;</span><br><span class="line">        <span class="comment">// perform handler callback </span></span><br><span class="line">        callCurrentHandlerOnDestroy();</span><br><span class="line"></span><br><span class="line">        <span class="comment">// calling server listener </span></span><br><span class="line">        <span class="keyword">for</span> (IServerListener listener : (ArrayList&lt;IServerListener&gt;)listeners.clone()) &#123;</span><br><span class="line">            <span class="keyword">try</span> &#123;</span><br><span class="line">                listener.onDestroy();</span><br><span class="line">            &#125; <span class="keyword">catch</span> (IOException ioe) &#123;&#125;</span><br><span class="line">		&#125;</span><br><span class="line">        listeners.clear();</span><br><span class="line">		</span><br><span class="line">        <span class="comment">// close default worker pool if exists</span></span><br><span class="line">        <span class="keyword">if</span> (defaultWorkerPool != <span class="keyword">null</span>) &#123;</span><br><span class="line">            WorkerpoolCloser workerpoolCloser = <span class="keyword">new</span> WorkerpoolCloser(Server.<span class="keyword">this</span>);</span><br><span class="line">            workerpoolCloser.start();</span><br><span class="line">        &#125;</span><br><span class="line">		</span><br><span class="line">        <span class="comment">// unset workerpool reference </span></span><br><span class="line">        workerpool = <span class="keyword">null</span>;</span><br><span class="line">    &#125;</span><br><span class="line">	</span><br><span class="line">	<span class="comment">//当新的客户端与服务端建立连接时，执行</span></span><br><span class="line">    <span class="function"><span class="keyword">public</span> <span class="keyword">void</span> <span class="title">onConnectionAccepted</span><span class="params">(IoChainableHandler ioHandler)</span> <span class="keyword">throws</span> IOException </span>&#123;</span><br><span class="line">        <span class="comment">// 如果达到了服务端的最大连接数，则禁止连接</span></span><br><span class="line">        <span class="keyword">if</span> (isMacConnectionSizeExceeded()) &#123;</span><br><span class="line">            <span class="comment">// create connection</span></span><br><span class="line">            NonBlockingConnection connection = <span class="keyword">new</span> NonBlockingConnection(connectionManager, HandlerAdapter.newInstance(<span class="keyword">null</span>));</span><br><span class="line">            init(connection, ioHandler);</span><br><span class="line">            </span><br><span class="line">            <span class="keyword">try</span> &#123;</span><br><span class="line">                onPreRejectConnection(connection);</span><br><span class="line">            &#125; <span class="keyword">catch</span> (IOException e) &#123;&#125;</span><br><span class="line">			</span><br><span class="line">            <span class="comment">// ... and than reject it</span></span><br><span class="line">            connection.closeQuietly();</span><br><span class="line">            <span class="comment">// wait while max connection size is exceeded</span></span><br><span class="line">            do &#123;</span><br><span class="line">                <span class="keyword">try</span> &#123;</span><br><span class="line">                    Thread.sleep(WAITTIME_MAXCONNECTION_EXCEEDED);</span><br><span class="line">                &#125; <span class="keyword">catch</span> (InterruptedException ie) &#123;&#125;</span><br><span class="line">            &#125; <span class="keyword">while</span> (isMacConnectionSizeExceeded());</span><br><span class="line">        &#125; <span class="keyword">else</span> &#123;</span><br><span class="line">            <span class="comment">// 正常处理客户端的连接事件</span></span><br><span class="line">            NonBlockingConnection connection = <span class="keyword">new</span> NonBlockingConnection(connectionManager, handlerAdapter.getConnectionInstance());</span><br><span class="line">            init(connection, ioHandler);</span><br><span class="line">        &#125;</span><br><span class="line">    &#125;</span><br><span class="line">	<span class="comment">//判断是否达到了服务端的最大连接数</span></span><br><span class="line">    <span class="function"><span class="keyword">private</span> <span class="keyword">boolean</span> <span class="title">isMacConnectionSizeExceeded</span><span class="params">()</span> </span>&#123;</span><br><span class="line">        <span class="keyword">return</span> (isMaxConnectionCheckAvtive &amp;&amp; </span><br><span class="line">                isOpen.get() &amp;&amp; </span><br><span class="line">                (acceptor.getDispatcherPool().getRoughNumRegisteredHandles() &gt;= maxConcurrentConnections) &amp;&amp;</span><br><span class="line">                (acceptor.getDispatcherPool().getNumRegisteredHandles() &gt;= maxConcurrentConnections));</span><br><span class="line">    &#125;</span><br><span class="line">    <span class="comment">//对连接进行必要的初始化设置</span></span><br><span class="line">    <span class="function"><span class="keyword">private</span> <span class="keyword">void</span> <span class="title">init</span><span class="params">(NonBlockingConnection connection, IoChainableHandler ioHandler)</span> <span class="keyword">throws</span> SocketTimeoutException, IOException </span>&#123;</span><br><span class="line">        <span class="comment">// set default flush properties</span></span><br><span class="line">        connection.setAutoflush(autoflush);</span><br><span class="line">        connection.setFlushmode(flushMode);</span><br><span class="line">        connection.setWorkerpool(workerpool);</span><br><span class="line">        </span><br><span class="line">        connection.init(ioHandler);</span><br><span class="line">			</span><br><span class="line">        <span class="comment">// 设置长连接闲置超时</span></span><br><span class="line">        connection.setIdleTimeoutMillis(idleTimeoutMillis);</span><br><span class="line">        <span class="comment">//设置连接超时</span></span><br><span class="line">        connection.setConnectionTimeoutMillis(connectionTimeoutMillis);</span><br><span class="line">        <span class="comment">// 限制输出流量</span></span><br><span class="line">        <span class="keyword">if</span> (writeRate != <span class="keyword">null</span>) &#123;</span><br><span class="line">             connection.setWriteTransferRate(writeRate);</span><br><span class="line">        &#125;</span><br><span class="line">		</span><br><span class="line">        <span class="comment">// and threshold</span></span><br><span class="line">        <span class="keyword">if</span> (maxReadBufferThreshold != <span class="keyword">null</span>) &#123;</span><br><span class="line">            connection.setMaxReadBufferThreshold(maxReadBufferThreshold);</span><br><span class="line">        &#125;</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure></p>
<p>　　每次有新的客户端连接后，都会执行onConnectionAccepted方法。该方法首先判断是否达到了服务端的最大连接数，如果没有，则进行正常的连接处理，包括连接参数初始化等。接着设置NonBlockingConnection和IoChainableHandler初始化参数。</p>
<h2 id="NonBlockingConnection"><a href="#NonBlockingConnection" class="headerlink" title="NonBlockingConnection"></a>NonBlockingConnection</h2><p>　　在客户端的代码中，我们新建了一个INonBlockingConnection对象，下面我们看看其关键的几行代码：<br><figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br></pre></td><td class="code"><pre><span class="line"><span class="function"><span class="keyword">private</span> <span class="title">NonBlockingConnection</span><span class="params">(InetSocketAddress remoteAddress, InetSocketAddress localAddress, <span class="keyword">boolean</span> waitForConnect, <span class="keyword">int</span> connectTimeoutMillis, <span class="keyword">final</span> Map&lt;String, Object&gt; options, <span class="keyword">final</span> SSLContext sslContext, <span class="keyword">boolean</span> isSecured,  IHandler appHdl, Executor workerpool, <span class="keyword">boolean</span> autoflush, FlushMode flushmode, Object attachment)</span> <span class="keyword">throws</span> IOException </span>&#123;</span><br><span class="line">    setFlushmode(flushmode);</span><br><span class="line">    setAutoflush(autoflush);</span><br><span class="line">    setWorkerpool(workerpool);</span><br><span class="line">	</span><br><span class="line">    setAttachment(attachment);</span><br><span class="line">	</span><br><span class="line">    handlerAdapterRef.set(HandlerAdapter.newInstance(appHdl));</span><br><span class="line">    isServerSide = <span class="keyword">false</span>;</span><br><span class="line">	</span><br><span class="line">    SocketChannel channel = openSocket(localAddress, options);</span><br><span class="line">	</span><br><span class="line">    IoConnector connector = getDefaultConnector();</span><br><span class="line">	</span><br><span class="line">	<span class="comment">// sync connect</span></span><br><span class="line">    <span class="keyword">if</span> (waitForConnect &amp;&amp; (connectTimeoutMillis &gt; <span class="number">0</span>)) &#123;</span><br><span class="line">        SyncIoConnectorCallback callback = <span class="keyword">new</span> SyncIoConnectorCallback(remoteAddress, channel, sslContext, isSecured, connectTimeoutMillis);</span><br><span class="line">        connector.connectAsync(channel, remoteAddress, connectTimeoutMillis, callback);</span><br><span class="line">        callback.connect();</span><br><span class="line">	<span class="comment">// async connect			</span></span><br><span class="line">    &#125; <span class="keyword">else</span> &#123;</span><br><span class="line">        IIoConnectorCallback callback = <span class="keyword">new</span> AsyncIoConnectorCallback(remoteAddress, channel, sslContext, isSecured, connectTimeoutMillis);</span><br><span class="line">        connector.connectAsync(channel, remoteAddress, connectTimeoutMillis, callback);</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="function"><span class="keyword">private</span> <span class="keyword">static</span> SocketChannel <span class="title">openSocket</span><span class="params">(InetSocketAddress localAddress, Map&lt;String ,Object&gt; options)</span> <span class="keyword">throws</span> IOException </span>&#123;</span><br><span class="line">    SocketChannel channel = SocketChannel.open();</span><br><span class="line"></span><br><span class="line">    <span class="keyword">for</span> (Entry&lt;String, Object&gt; entry : options.entrySet()) &#123;</span><br><span class="line">        IoProvider.setOption(channel.socket(), entry.getKey(), entry.getValue());</span><br><span class="line">    &#125;</span><br><span class="line">        </span><br><span class="line">    <span class="keyword">if</span> (localAddress != <span class="keyword">null</span>) &#123;</span><br><span class="line">        channel.socket().bind(localAddress);</span><br><span class="line">    &#125;</span><br><span class="line">    <span class="keyword">return</span> channel;</span><br><span class="line">&#125;</span><br><span class="line"><span class="function"><span class="keyword">private</span> <span class="keyword">synchronized</span> <span class="keyword">static</span> IoConnector <span class="title">getDefaultConnector</span><span class="params">()</span> </span>&#123;</span><br><span class="line">    <span class="keyword">if</span> (defaultConnector == <span class="keyword">null</span>) &#123;</span><br><span class="line">        defaultConnector = <span class="keyword">new</span> IoConnector(<span class="string">"default"</span>);</span><br><span class="line"></span><br><span class="line">        Thread t = <span class="keyword">new</span> Thread(defaultConnector);</span><br><span class="line">        t.setDaemon(<span class="keyword">true</span>);</span><br><span class="line">        t.start();</span><br><span class="line">    &#125;</span><br><span class="line">    <span class="keyword">return</span> defaultConnector;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure></p>
<p>　　在构造方法中建立连接，并生成IoConnector用来管理连接，然后connector开始启动，做一些初始化的工作：其中connectAsync方法会执行会产生一个RegisterTask任务到IoConnector。下面我们终端关注 IoConnector 的run、connectAsync等方法<br><figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br><span class="line">50</span><br><span class="line">51</span><br><span class="line">52</span><br><span class="line">53</span><br><span class="line">54</span><br><span class="line">55</span><br><span class="line">56</span><br><span class="line">57</span><br><span class="line">58</span><br><span class="line">59</span><br><span class="line">60</span><br><span class="line">61</span><br><span class="line">62</span><br><span class="line">63</span><br><span class="line">64</span><br><span class="line">65</span><br><span class="line">66</span><br><span class="line">67</span><br><span class="line">68</span><br><span class="line">69</span><br><span class="line">70</span><br><span class="line">71</span><br><span class="line">72</span><br><span class="line">73</span><br><span class="line">74</span><br><span class="line">75</span><br><span class="line">76</span><br><span class="line">77</span><br><span class="line">78</span><br><span class="line">79</span><br><span class="line">80</span><br><span class="line">81</span><br><span class="line">82</span><br><span class="line">83</span><br><span class="line">84</span><br><span class="line">85</span><br><span class="line">86</span><br><span class="line">87</span><br><span class="line">88</span><br><span class="line">89</span><br><span class="line">90</span><br><span class="line">91</span><br><span class="line">92</span><br><span class="line">93</span><br><span class="line">94</span><br><span class="line">95</span><br><span class="line">96</span><br><span class="line">97</span><br><span class="line">98</span><br><span class="line">99</span><br><span class="line">100</span><br><span class="line">101</span><br><span class="line">102</span><br><span class="line">103</span><br><span class="line">104</span><br><span class="line">105</span><br><span class="line">106</span><br><span class="line">107</span><br><span class="line">108</span><br><span class="line">109</span><br><span class="line">110</span><br><span class="line">111</span><br><span class="line">112</span><br><span class="line">113</span><br><span class="line">114</span><br><span class="line">115</span><br><span class="line">116</span><br><span class="line">117</span><br><span class="line">118</span><br><span class="line">119</span><br><span class="line">120</span><br><span class="line">121</span><br><span class="line">122</span><br><span class="line">123</span><br><span class="line">124</span><br><span class="line">125</span><br><span class="line">126</span><br><span class="line">127</span><br><span class="line">128</span><br><span class="line">129</span><br><span class="line">130</span><br><span class="line">131</span><br><span class="line">132</span><br><span class="line">133</span><br><span class="line">134</span><br><span class="line">135</span><br><span class="line">136</span><br><span class="line">137</span><br><span class="line">138</span><br><span class="line">139</span><br><span class="line">140</span><br><span class="line">141</span><br><span class="line">142</span><br><span class="line">143</span><br><span class="line">144</span><br><span class="line">145</span><br><span class="line">146</span><br><span class="line">147</span><br><span class="line">148</span><br><span class="line">149</span><br><span class="line">150</span><br><span class="line">151</span><br><span class="line">152</span><br><span class="line">153</span><br><span class="line">154</span><br><span class="line">155</span><br><span class="line">156</span><br><span class="line">157</span><br><span class="line">158</span><br><span class="line">159</span><br><span class="line">160</span><br><span class="line">161</span><br><span class="line">162</span><br><span class="line">163</span><br><span class="line">164</span><br><span class="line">165</span><br><span class="line">166</span><br><span class="line">167</span><br><span class="line">168</span><br><span class="line">169</span><br><span class="line">170</span><br><span class="line">171</span><br><span class="line">172</span><br><span class="line">173</span><br><span class="line">174</span><br><span class="line">175</span><br><span class="line">176</span><br><span class="line">177</span><br><span class="line">178</span><br><span class="line">179</span><br><span class="line">180</span><br><span class="line">181</span><br><span class="line">182</span><br><span class="line">183</span><br><span class="line">184</span><br><span class="line">185</span><br><span class="line">186</span><br><span class="line">187</span><br><span class="line">188</span><br><span class="line">189</span><br><span class="line">190</span><br><span class="line">191</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">final</span> <span class="class"><span class="keyword">class</span> <span class="title">IoConnector</span> <span class="keyword">extends</span> <span class="title">MonitoredSelector</span> <span class="keyword">implements</span> <span class="title">Runnable</span>, <span class="title">Closeable</span> </span>&#123;</span><br><span class="line">    <span class="keyword">private</span> <span class="keyword">final</span> TimeoutCheckTask timeoutCheckTask = <span class="keyword">new</span> TimeoutCheckTask();</span><br><span class="line">    <span class="keyword">private</span> TimerTask watchDogTask;</span><br><span class="line">    <span class="comment">// selector </span></span><br><span class="line">    <span class="keyword">private</span> <span class="keyword">final</span> Selector selector;</span><br><span class="line">    <span class="comment">// queues</span></span><br><span class="line">    <span class="keyword">private</span> <span class="keyword">final</span> ConcurrentLinkedQueue&lt;Runnable&gt; taskQueue = <span class="keyword">new</span> ConcurrentLinkedQueue&lt;Runnable&gt;();</span><br><span class="line"></span><br><span class="line">    <span class="function"><span class="keyword">public</span> <span class="title">IoConnector</span><span class="params">(String name)</span> </span>&#123;</span><br><span class="line">        <span class="keyword">try</span> &#123;</span><br><span class="line">            selector = Selector.open();</span><br><span class="line">        &#125; <span class="keyword">catch</span> (IOException ioe) &#123;&#125;     </span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="function"><span class="keyword">public</span> <span class="keyword">void</span> <span class="title">run</span><span class="params">()</span> </span>&#123;</span><br><span class="line">        </span><br><span class="line">        <span class="keyword">int</span> handledTasks = <span class="number">0</span>;</span><br><span class="line"></span><br><span class="line">        <span class="keyword">while</span>(isOpen.get()) &#123;</span><br><span class="line">            <span class="keyword">try</span> &#123;</span><br><span class="line">                handledTasks = performTaskQueue();</span><br><span class="line">                </span><br><span class="line">                <span class="keyword">int</span> eventCount = selector.select(<span class="number">1000</span>);</span><br><span class="line">                </span><br><span class="line">                <span class="keyword">if</span> (eventCount &gt; <span class="number">0</span>) &#123;</span><br><span class="line">                    handleConnect();</span><br><span class="line">                &#125; <span class="keyword">else</span> &#123;</span><br><span class="line">                	checkForLooping(handledTasks);</span><br><span class="line">                &#125;</span><br><span class="line">            &#125; <span class="keyword">catch</span> (Exception e) &#123;&#125;</span><br><span class="line">        &#125;</span><br><span class="line"></span><br><span class="line">        <span class="keyword">try</span> &#123;</span><br><span class="line">            selector.close();</span><br><span class="line">        &#125; <span class="keyword">catch</span> (Exception e) &#123;&#125;</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="function"><span class="keyword">private</span> <span class="keyword">int</span> <span class="title">performTaskQueue</span><span class="params">()</span> <span class="keyword">throws</span> IOException </span>&#123;</span><br><span class="line"></span><br><span class="line">        <span class="keyword">int</span> handledTasks = <span class="number">0</span>;</span><br><span class="line"></span><br><span class="line">        <span class="keyword">while</span> (<span class="keyword">true</span>) &#123;</span><br><span class="line">            Runnable task = taskQueue.poll();</span><br><span class="line"></span><br><span class="line">            <span class="keyword">if</span> (task == <span class="keyword">null</span>) &#123;</span><br><span class="line">                <span class="keyword">return</span> handledTasks;</span><br><span class="line"></span><br><span class="line">            &#125; <span class="keyword">else</span> &#123;</span><br><span class="line">                task.run();</span><br><span class="line">                handledTasks++;</span><br><span class="line">            &#125;</span><br><span class="line">        &#125;</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="function"><span class="keyword">private</span> <span class="keyword">void</span> <span class="title">handleConnect</span><span class="params">()</span> </span>&#123;</span><br><span class="line">        Set&lt;SelectionKey&gt; selectedEventKeys = selector.selectedKeys();</span><br><span class="line"></span><br><span class="line">        Iterator&lt;SelectionKey&gt; it = selectedEventKeys.iterator();</span><br><span class="line"></span><br><span class="line">        <span class="keyword">while</span> (it.hasNext()) &#123;</span><br><span class="line">            SelectionKey eventKey = it.next();</span><br><span class="line">            it.remove();</span><br><span class="line"></span><br><span class="line">            RegisterTask registerTask = (RegisterTask) eventKey.attachment();</span><br><span class="line"></span><br><span class="line">            <span class="keyword">if</span> (eventKey.isValid() &amp;&amp; eventKey.isConnectable()) &#123;</span><br><span class="line">                <span class="keyword">try</span> &#123;</span><br><span class="line">                    <span class="keyword">boolean</span> isConnected = ((SocketChannel) eventKey.channel()).finishConnect();</span><br><span class="line">                    <span class="keyword">if</span> (isConnected) &#123;</span><br><span class="line">						eventKey.cancel();</span><br><span class="line">                    	registerTask.callback.onConnectionEstablished();</span><br><span class="line">					&#125;</span><br><span class="line">                &#125; <span class="keyword">catch</span> (IOException ioe) &#123;&#125;</span><br><span class="line">            &#125;</span><br><span class="line">        &#125;</span><br><span class="line">    &#125;</span><br><span class="line">      </span><br><span class="line">    <span class="function"><span class="keyword">public</span> <span class="keyword">void</span> <span class="title">connectAsync</span><span class="params">(SocketChannel channel, InetSocketAddress remoteAddress, <span class="keyword">long</span> connectTimeoutMillis, IIoConnectorCallback callback)</span> <span class="keyword">throws</span> IOException </span>&#123;</span><br><span class="line">        RegisterTask registerTask = <span class="keyword">new</span> RegisterTask(channel, callback, remoteAddress, System.currentTimeMillis() + (<span class="keyword">long</span>) connectTimeoutMillis);</span><br><span class="line">        addToTaskQueue(registerTask);</span><br><span class="line">                </span><br><span class="line">        <span class="keyword">if</span> (connectTimeoutMillis &gt;= <span class="number">1000</span>) &#123;</span><br><span class="line">            updateTimeoutCheckPeriod(connectTimeoutMillis / <span class="number">5</span>);</span><br><span class="line">        &#125; <span class="keyword">else</span> &#123;</span><br><span class="line">            updateTimeoutCheckPeriod(<span class="number">200</span>);</span><br><span class="line">        &#125;</span><br><span class="line">    &#125;</span><br><span class="line">    </span><br><span class="line">    <span class="function"><span class="keyword">private</span> <span class="keyword">void</span> <span class="title">addToTaskQueue</span><span class="params">(Runnable task)</span> </span>&#123;</span><br><span class="line">        taskQueue.add(task);</span><br><span class="line">        selector.wakeup();</span><br><span class="line">    &#125;</span><br><span class="line">    </span><br><span class="line">    <span class="keyword">private</span> <span class="keyword">final</span> <span class="class"><span class="keyword">class</span> <span class="title">RegisterTask</span> <span class="keyword">implements</span> <span class="title">Runnable</span> </span>&#123;</span><br><span class="line"></span><br><span class="line">        <span class="keyword">private</span> <span class="keyword">final</span> SocketChannel channel;</span><br><span class="line">        <span class="keyword">private</span> <span class="keyword">final</span> IIoConnectorCallback callback;</span><br><span class="line">        <span class="keyword">private</span> <span class="keyword">final</span> InetSocketAddress remoteAddress;</span><br><span class="line">        <span class="keyword">private</span> <span class="keyword">final</span> <span class="keyword">long</span> expireTime;</span><br><span class="line">        </span><br><span class="line">        <span class="keyword">private</span> SelectionKey selectionKey;</span><br><span class="line">        </span><br><span class="line">        <span class="function"><span class="keyword">public</span> <span class="title">RegisterTask</span><span class="params">(SocketChannel channel, IIoConnectorCallback callback, InetSocketAddress remoteAddress, <span class="keyword">long</span> expireTime)</span> <span class="keyword">throws</span> IOException </span>&#123;</span><br><span class="line">            <span class="keyword">this</span>.channel = channel;</span><br><span class="line">            <span class="keyword">this</span>.callback = callback;</span><br><span class="line">            <span class="keyword">this</span>.remoteAddress = remoteAddress;</span><br><span class="line">            <span class="keyword">this</span>.expireTime = expireTime;</span><br><span class="line">            </span><br><span class="line">            channel.configureBlocking(<span class="keyword">false</span>);</span><br><span class="line">        &#125;</span><br><span class="line">        </span><br><span class="line">        <span class="function"><span class="keyword">boolean</span> <span class="title">isExpired</span><span class="params">(<span class="keyword">long</span> currentTime)</span> </span>&#123;</span><br><span class="line">            <span class="keyword">return</span> (currentTime &gt; expireTime); </span><br><span class="line">        &#125;</span><br><span class="line">        </span><br><span class="line">        <span class="function"><span class="keyword">public</span> <span class="keyword">void</span> <span class="title">run</span><span class="params">()</span> </span>&#123;</span><br><span class="line">          </span><br><span class="line">            selectionKey = <span class="keyword">null</span>;</span><br><span class="line">            <span class="keyword">try</span> &#123;</span><br><span class="line">                selectionKey = channel.register(selector, SelectionKey.OP_CONNECT);</span><br><span class="line">                selectionKey.attach(<span class="keyword">this</span>);</span><br><span class="line">                connect(channel, remoteAddress);</span><br><span class="line">            </span><br><span class="line">            &#125; <span class="keyword">catch</span> (IOException ioe) &#123;&#125;</span><br><span class="line">        &#125;</span><br><span class="line">        </span><br><span class="line">        <span class="function"><span class="keyword">private</span> <span class="keyword">void</span> <span class="title">connect</span><span class="params">(SocketChannel channel, InetSocketAddress remoteAddress)</span> <span class="keyword">throws</span> IOException </span>&#123;</span><br><span class="line">            <span class="keyword">try</span> &#123;</span><br><span class="line">                channel.connect(remoteAddress);</span><br><span class="line">            &#125; <span class="keyword">catch</span> (UnresolvedAddressException uae) &#123;</span><br><span class="line">                <span class="keyword">throw</span> <span class="keyword">new</span> IOException(<span class="string">"connecting "</span> + remoteAddress + <span class="string">" failed "</span> + uae.toString());</span><br><span class="line">            &#125; </span><br><span class="line">        &#125;</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    </span><br><span class="line">    <span class="function"><span class="keyword">void</span> <span class="title">updateTimeoutCheckPeriod</span><span class="params">(<span class="keyword">long</span> requiredMinPeriod)</span> </span>&#123;</span><br><span class="line"></span><br><span class="line">        <span class="keyword">synchronized</span> (<span class="keyword">this</span>) &#123;</span><br><span class="line"></span><br><span class="line">            <span class="comment">// if non watchdog task already exists and the required period is smaller than current one -&gt; return</span></span><br><span class="line">            <span class="keyword">if</span> ((watchDogTask != <span class="keyword">null</span>) &amp;&amp; (watchDogPeriodMillis &lt;= requiredMinPeriod)) &#123;</span><br><span class="line">                <span class="keyword">return</span>;</span><br><span class="line">            &#125;</span><br><span class="line">    </span><br><span class="line">            <span class="comment">// set watch dog period</span></span><br><span class="line">            watchDogPeriodMillis = requiredMinPeriod;</span><br><span class="line">            <span class="keyword">if</span> (LOG.isLoggable(Level.FINE)) &#123;</span><br><span class="line">                LOG.fine(<span class="string">"update watchdog period "</span> + DataConverter.toFormatedDuration(watchDogPeriodMillis));</span><br><span class="line">            &#125;</span><br><span class="line">    </span><br><span class="line">            <span class="comment">// if watchdog task task already exits -&gt; terminate it</span></span><br><span class="line">            <span class="keyword">if</span> (watchDogTask != <span class="keyword">null</span>) &#123;</span><br><span class="line">                watchDogTask.cancel();</span><br><span class="line">                watchDogTask = <span class="keyword">null</span>;</span><br><span class="line">            &#125;</span><br><span class="line">            </span><br><span class="line">            <span class="comment">// create and run new watchdog task</span></span><br><span class="line">            watchDogTask = <span class="keyword">new</span> TimerTask() &#123;</span><br><span class="line">        </span><br><span class="line">                <span class="function"><span class="keyword">public</span> <span class="keyword">void</span> <span class="title">run</span><span class="params">()</span> </span>&#123;</span><br><span class="line">                    addToTaskQueue(timeoutCheckTask);</span><br><span class="line">                &#125;</span><br><span class="line">            &#125;;</span><br><span class="line">            IoProvider.getTimer().schedule(watchDogTask, watchDogPeriodMillis, watchDogPeriodMillis);</span><br><span class="line">        &#125;</span><br><span class="line">    &#125;   </span><br><span class="line">    </span><br><span class="line">    <span class="keyword">private</span> <span class="keyword">final</span> <span class="class"><span class="keyword">class</span> <span class="title">TimeoutCheckTask</span> <span class="keyword">implements</span> <span class="title">Runnable</span> </span>&#123;</span><br><span class="line">        </span><br><span class="line">        <span class="function"><span class="keyword">public</span> <span class="keyword">void</span> <span class="title">run</span><span class="params">()</span> </span>&#123;</span><br><span class="line">            </span><br><span class="line">            <span class="keyword">try</span> &#123;</span><br><span class="line">                <span class="keyword">long</span> currentMillis = System.currentTimeMillis();</span><br><span class="line">                </span><br><span class="line">                <span class="keyword">for</span> (SelectionKey selectionKey : selector.keys()) &#123;</span><br><span class="line">                    RegisterTask registerTask = (RegisterTask) selectionKey.attachment();</span><br><span class="line">                    <span class="keyword">if</span> (registerTask.isExpired(currentMillis)) &#123;</span><br><span class="line">                        selectionKey.cancel();</span><br><span class="line">                        registerTask.callback.onConnectTimeout();</span><br><span class="line">                    &#125;</span><br><span class="line">                &#125;</span><br><span class="line">            &#125; <span class="keyword">catch</span> (Exception e) &#123;</span><br><span class="line">                <span class="comment">// eat and log exception</span></span><br><span class="line">                <span class="keyword">if</span> (LOG.isLoggable(Level.FINE)) &#123;</span><br><span class="line">                    LOG.fine(<span class="string">"error occured by performing timeout check task "</span> + e.toString());</span><br><span class="line">                &#125;</span><br><span class="line">            &#125;</span><br><span class="line">        &#125;</span><br><span class="line">    &#125;    </span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure></p>
<p>　　可以看到，最后是在内部类RegisterTask中完成了注册事件。</p>

      
    </div>
    <footer class="article-footer">
      <a data-url="http://yoursite.com/2016/01/02/nio/9.xSocket系列二之源码分析一/" data-id="cijzzpv6d004d1cfs5n8ob37z" class="article-share-link">Share</a>
      
      
  <ul class="article-tag-list"><li class="article-tag-list-item"><a class="article-tag-list-link" href="/tags/java/">java</a></li><li class="article-tag-list-item"><a class="article-tag-list-link" href="/tags/xSocket/">xSocket</a></li></ul>

    </footer>
  </div>
  
    
<nav id="article-nav">
  
    <a href="/2016/01/02/nio/10.xSocket系列三之源码分析二/" id="article-nav-newer" class="article-nav-link-wrap">
      <strong class="article-nav-caption">Newer</strong>
      <div class="article-nav-title">
        
          xSocket系列三之源码分析二
        
      </div>
    </a>
  
  
    <a href="/2016/01/02/nio/8.xSocket系列一之入门/" id="article-nav-older" class="article-nav-link-wrap">
      <strong class="article-nav-caption">Older</strong>
      <div class="article-nav-title">xSocket系列一之入门</div>
    </a>
  
</nav>

  
</article>

</section>
        
          <aside id="sidebar">
  
    
  <div class="widget-wrap">
    <h3 class="widget-title">Categories</h3>
    <div class="widget">
      <ul class="category-list"><li class="category-list-item"><a class="category-list-link" href="/categories/cache/">cache</a><span class="category-list-count">3</span></li><li class="category-list-item"><a class="category-list-link" href="/categories/database/">database</a><span class="category-list-count">13</span></li><li class="category-list-item"><a class="category-list-link" href="/categories/docker/">docker</a><span class="category-list-count">6</span></li><li class="category-list-item"><a class="category-list-link" href="/categories/gis/">gis</a><span class="category-list-count">4</span></li><li class="category-list-item"><a class="category-list-link" href="/categories/git/">git</a><span class="category-list-count">2</span></li><li class="category-list-item"><a class="category-list-link" href="/categories/go/">go</a><span class="category-list-count">1</span></li><li class="category-list-item"><a class="category-list-link" href="/categories/gradle/">gradle</a><span class="category-list-count">1</span></li><li class="category-list-item"><a class="category-list-link" href="/categories/groovy/">groovy</a><span class="category-list-count">1</span></li><li class="category-list-item"><a class="category-list-link" href="/categories/hadoop/">hadoop</a><span class="category-list-count">1</span></li><li class="category-list-item"><a class="category-list-link" href="/categories/java/">java</a><span class="category-list-count">18</span></li><li class="category-list-item"><a class="category-list-link" href="/categories/linux/">linux</a><span class="category-list-count">4</span></li><li class="category-list-item"><a class="category-list-link" href="/categories/log/">log</a><span class="category-list-count">11</span></li><li class="category-list-item"><a class="category-list-link" href="/categories/mongodb/">mongodb</a><span class="category-list-count">14</span></li><li class="category-list-item"><a class="category-list-link" href="/categories/mq/">mq</a><span class="category-list-count">6</span></li><li class="category-list-item"><a class="category-list-link" href="/categories/mybatis/">mybatis</a><span class="category-list-count">9</span></li><li class="category-list-item"><a class="category-list-link" href="/categories/netty/">netty</a><span class="category-list-count">1</span></li><li class="category-list-item"><a class="category-list-link" href="/categories/nginx/">nginx</a><span class="category-list-count">3</span></li><li class="category-list-item"><a class="category-list-link" href="/categories/nio/">nio</a><span class="category-list-count">19</span></li><li class="category-list-item"><a class="category-list-link" href="/categories/nodejs/">nodejs</a><span class="category-list-count">1</span></li><li class="category-list-item"><a class="category-list-link" href="/categories/redis/">redis</a><span class="category-list-count">6</span></li><li class="category-list-item"><a class="category-list-link" href="/categories/rpc/">rpc</a><span class="category-list-count">14</span></li><li class="category-list-item"><a class="category-list-link" href="/categories/spring/">spring</a><span class="category-list-count">5</span></li><li class="category-list-item"><a class="category-list-link" href="/categories/tomcat/">tomcat</a><span class="category-list-count">2</span></li><li class="category-list-item"><a class="category-list-link" href="/categories/zookeeper/">zookeeper</a><span class="category-list-count">2</span></li><li class="category-list-item"><a class="category-list-link" href="/categories/杂项/">杂项</a><span class="category-list-count">2</span></li></ul>
    </div>
  </div>

  
    
  <div class="widget-wrap">
    <h3 class="widget-title">Tags</h3>
    <div class="widget">
      <ul class="tag-list"><li class="tag-list-item"><a class="tag-list-link" href="/tags/aop/">aop</a><span class="tag-list-count">8</span></li><li class="tag-list-item"><a class="tag-list-link" href="/tags/aspectj/">aspectj</a><span class="tag-list-count">3</span></li><li class="tag-list-item"><a class="tag-list-link" href="/tags/cache/">cache</a><span class="tag-list-count">3</span></li><li class="tag-list-item"><a class="tag-list-link" href="/tags/classloader/">classloader</a><span class="tag-list-count">1</span></li><li class="tag-list-item"><a class="tag-list-link" href="/tags/common-loggings/">common-loggings</a><span class="tag-list-count">1</span></li><li class="tag-list-item"><a class="tag-list-link" href="/tags/commonjs/">commonjs</a><span class="tag-list-count">4</span></li><li class="tag-list-item"><a class="tag-list-link" href="/tags/database/">database</a><span class="tag-list-count">10</span></li><li class="tag-list-item"><a class="tag-list-link" href="/tags/docker/">docker</a><span class="tag-list-count">6</span></li><li class="tag-list-item"><a class="tag-list-link" href="/tags/dubbo/">dubbo</a><span class="tag-list-count">1</span></li><li class="tag-list-item"><a class="tag-list-link" href="/tags/fastdfs/">fastdfs</a><span class="tag-list-count">1</span></li><li class="tag-list-item"><a class="tag-list-link" href="/tags/gclib/">gclib</a><span class="tag-list-count">2</span></li><li class="tag-list-item"><a class="tag-list-link" href="/tags/geohash/">geohash</a><span class="tag-list-count">1</span></li><li class="tag-list-item"><a class="tag-list-link" href="/tags/gis/">gis</a><span class="tag-list-count">1</span></li><li class="tag-list-item"><a class="tag-list-link" href="/tags/git/">git</a><span class="tag-list-count">2</span></li><li class="tag-list-item"><a class="tag-list-link" href="/tags/go/">go</a><span class="tag-list-count">1</span></li><li class="tag-list-item"><a class="tag-list-link" href="/tags/gradle/">gradle</a><span class="tag-list-count">1</span></li><li class="tag-list-item"><a class="tag-list-link" href="/tags/groovy/">groovy</a><span class="tag-list-count">1</span></li><li class="tag-list-item"><a class="tag-list-link" href="/tags/hadoop/">hadoop</a><span class="tag-list-count">1</span></li><li class="tag-list-item"><a class="tag-list-link" href="/tags/hessisan/">hessisan</a><span class="tag-list-count">3</span></li><li class="tag-list-item"><a class="tag-list-link" href="/tags/java/">java</a><span class="tag-list-count">48</span></li><li class="tag-list-item"><a class="tag-list-link" href="/tags/javassist/">javassist</a><span class="tag-list-count">1</span></li><li class="tag-list-item"><a class="tag-list-link" href="/tags/kafka/">kafka</a><span class="tag-list-count">3</span></li><li class="tag-list-item"><a class="tag-list-link" href="/tags/linux/">linux</a><span class="tag-list-count">4</span></li><li class="tag-list-item"><a class="tag-list-link" href="/tags/log/">log</a><span class="tag-list-count">11</span></li><li class="tag-list-item"><a class="tag-list-link" href="/tags/log4j/">log4j</a><span class="tag-list-count">4</span></li><li class="tag-list-item"><a class="tag-list-link" href="/tags/logback/">logback</a><span class="tag-list-count">5</span></li><li class="tag-list-item"><a class="tag-list-link" href="/tags/map/">map</a><span class="tag-list-count">1</span></li><li class="tag-list-item"><a class="tag-list-link" href="/tags/memecached/">memecached</a><span class="tag-list-count">2</span></li><li class="tag-list-item"><a class="tag-list-link" href="/tags/mina/">mina</a><span class="tag-list-count">5</span></li><li class="tag-list-item"><a class="tag-list-link" href="/tags/mongodb/">mongodb</a><span class="tag-list-count">14</span></li><li class="tag-list-item"><a class="tag-list-link" href="/tags/mq/">mq</a><span class="tag-list-count">6</span></li><li class="tag-list-item"><a class="tag-list-link" href="/tags/mqtt/">mqtt</a><span class="tag-list-count">2</span></li><li class="tag-list-item"><a class="tag-list-link" href="/tags/mybatis/">mybatis</a><span class="tag-list-count">9</span></li><li class="tag-list-item"><a class="tag-list-link" href="/tags/netty/">netty</a><span class="tag-list-count">1</span></li><li class="tag-list-item"><a class="tag-list-link" href="/tags/nginx/">nginx</a><span class="tag-list-count">3</span></li><li class="tag-list-item"><a class="tag-list-link" href="/tags/nio/">nio</a><span class="tag-list-count">5</span></li><li class="tag-list-item"><a class="tag-list-link" href="/tags/nodejs/">nodejs</a><span class="tag-list-count">1</span></li><li class="tag-list-item"><a class="tag-list-link" href="/tags/postgresql/">postgresql</a><span class="tag-list-count">2</span></li><li class="tag-list-item"><a class="tag-list-link" href="/tags/protobuf/">protobuf</a><span class="tag-list-count">1</span></li><li class="tag-list-item"><a class="tag-list-link" href="/tags/proxy/">proxy</a><span class="tag-list-count">1</span></li><li class="tag-list-item"><a class="tag-list-link" href="/tags/push/">push</a><span class="tag-list-count">1</span></li><li class="tag-list-item"><a class="tag-list-link" href="/tags/rabbitmq/">rabbitmq</a><span class="tag-list-count">3</span></li><li class="tag-list-item"><a class="tag-list-link" href="/tags/redis/">redis</a><span class="tag-list-count">6</span></li><li class="tag-list-item"><a class="tag-list-link" href="/tags/rpc/">rpc</a><span class="tag-list-count">14</span></li><li class="tag-list-item"><a class="tag-list-link" href="/tags/sitemesh/">sitemesh</a><span class="tag-list-count">1</span></li><li class="tag-list-item"><a class="tag-list-link" href="/tags/sld/">sld</a><span class="tag-list-count">1</span></li><li class="tag-list-item"><a class="tag-list-link" href="/tags/slf4j/">slf4j</a><span class="tag-list-count">1</span></li><li class="tag-list-item"><a class="tag-list-link" href="/tags/socket/">socket</a><span class="tag-list-count">7</span></li><li class="tag-list-item"><a class="tag-list-link" href="/tags/spatialite-for-android/">spatialite for android</a><span class="tag-list-count">1</span></li><li class="tag-list-item"><a class="tag-list-link" href="/tags/spi/">spi</a><span class="tag-list-count">1</span></li><li class="tag-list-item"><a class="tag-list-link" href="/tags/spring/">spring</a><span class="tag-list-count">13</span></li><li class="tag-list-item"><a class="tag-list-link" href="/tags/tomcat/">tomcat</a><span class="tag-list-count">2</span></li><li class="tag-list-item"><a class="tag-list-link" href="/tags/transaction/">transaction</a><span class="tag-list-count">1</span></li><li class="tag-list-item"><a class="tag-list-link" href="/tags/web/">web</a><span class="tag-list-count">1</span></li><li class="tag-list-item"><a class="tag-list-link" href="/tags/xSocket/">xSocket</a><span class="tag-list-count">7</span></li><li class="tag-list-item"><a class="tag-list-link" href="/tags/zbus/">zbus</a><span class="tag-list-count">1</span></li><li class="tag-list-item"><a class="tag-list-link" href="/tags/zookeeper/">zookeeper</a><span class="tag-list-count">2</span></li><li class="tag-list-item"><a class="tag-list-link" href="/tags/数据结构/">数据结构</a><span class="tag-list-count">2</span></li></ul>
    </div>
  </div>

  
    
  <div class="widget-wrap">
    <h3 class="widget-title">Tag Cloud</h3>
    <div class="widget tagcloud">
      <a href="/tags/aop/" style="font-size: 15.38px;">aop</a> <a href="/tags/aspectj/" style="font-size: 11.54px;">aspectj</a> <a href="/tags/cache/" style="font-size: 11.54px;">cache</a> <a href="/tags/classloader/" style="font-size: 10px;">classloader</a> <a href="/tags/common-loggings/" style="font-size: 10px;">common-loggings</a> <a href="/tags/commonjs/" style="font-size: 12.31px;">commonjs</a> <a href="/tags/database/" style="font-size: 16.92px;">database</a> <a href="/tags/docker/" style="font-size: 13.85px;">docker</a> <a href="/tags/dubbo/" style="font-size: 10px;">dubbo</a> <a href="/tags/fastdfs/" style="font-size: 10px;">fastdfs</a> <a href="/tags/gclib/" style="font-size: 10.77px;">gclib</a> <a href="/tags/geohash/" style="font-size: 10px;">geohash</a> <a href="/tags/gis/" style="font-size: 10px;">gis</a> <a href="/tags/git/" style="font-size: 10.77px;">git</a> <a href="/tags/go/" style="font-size: 10px;">go</a> <a href="/tags/gradle/" style="font-size: 10px;">gradle</a> <a href="/tags/groovy/" style="font-size: 10px;">groovy</a> <a href="/tags/hadoop/" style="font-size: 10px;">hadoop</a> <a href="/tags/hessisan/" style="font-size: 11.54px;">hessisan</a> <a href="/tags/java/" style="font-size: 20px;">java</a> <a href="/tags/javassist/" style="font-size: 10px;">javassist</a> <a href="/tags/kafka/" style="font-size: 11.54px;">kafka</a> <a href="/tags/linux/" style="font-size: 12.31px;">linux</a> <a href="/tags/log/" style="font-size: 17.69px;">log</a> <a href="/tags/log4j/" style="font-size: 12.31px;">log4j</a> <a href="/tags/logback/" style="font-size: 13.08px;">logback</a> <a href="/tags/map/" style="font-size: 10px;">map</a> <a href="/tags/memecached/" style="font-size: 10.77px;">memecached</a> <a href="/tags/mina/" style="font-size: 13.08px;">mina</a> <a href="/tags/mongodb/" style="font-size: 19.23px;">mongodb</a> <a href="/tags/mq/" style="font-size: 13.85px;">mq</a> <a href="/tags/mqtt/" style="font-size: 10.77px;">mqtt</a> <a href="/tags/mybatis/" style="font-size: 16.15px;">mybatis</a> <a href="/tags/netty/" style="font-size: 10px;">netty</a> <a href="/tags/nginx/" style="font-size: 11.54px;">nginx</a> <a href="/tags/nio/" style="font-size: 13.08px;">nio</a> <a href="/tags/nodejs/" style="font-size: 10px;">nodejs</a> <a href="/tags/postgresql/" style="font-size: 10.77px;">postgresql</a> <a href="/tags/protobuf/" style="font-size: 10px;">protobuf</a> <a href="/tags/proxy/" style="font-size: 10px;">proxy</a> <a href="/tags/push/" style="font-size: 10px;">push</a> <a href="/tags/rabbitmq/" style="font-size: 11.54px;">rabbitmq</a> <a href="/tags/redis/" style="font-size: 13.85px;">redis</a> <a href="/tags/rpc/" style="font-size: 19.23px;">rpc</a> <a href="/tags/sitemesh/" style="font-size: 10px;">sitemesh</a> <a href="/tags/sld/" style="font-size: 10px;">sld</a> <a href="/tags/slf4j/" style="font-size: 10px;">slf4j</a> <a href="/tags/socket/" style="font-size: 14.62px;">socket</a> <a href="/tags/spatialite-for-android/" style="font-size: 10px;">spatialite for android</a> <a href="/tags/spi/" style="font-size: 10px;">spi</a> <a href="/tags/spring/" style="font-size: 18.46px;">spring</a> <a href="/tags/tomcat/" style="font-size: 10.77px;">tomcat</a> <a href="/tags/transaction/" style="font-size: 10px;">transaction</a> <a href="/tags/web/" style="font-size: 10px;">web</a> <a href="/tags/xSocket/" style="font-size: 14.62px;">xSocket</a> <a href="/tags/zbus/" style="font-size: 10px;">zbus</a> <a href="/tags/zookeeper/" style="font-size: 10.77px;">zookeeper</a> <a href="/tags/数据结构/" style="font-size: 10.77px;">数据结构</a>
    </div>
  </div>

  
    
  <div class="widget-wrap">
    <h3 class="widget-title">Archives</h3>
    <div class="widget">
      <ul class="archive-list"><li class="archive-list-item"><a class="archive-list-link" href="/archives/2016/01/">January 2016</a><span class="archive-list-count">67</span></li><li class="archive-list-item"><a class="archive-list-link" href="/archives/2015/12/">December 2015</a><span class="archive-list-count">81</span></li><li class="archive-list-item"><a class="archive-list-link" href="/archives/2015/11/">November 2015</a><span class="archive-list-count">2</span></li></ul>
    </div>
  </div>

  
    
  <div class="widget-wrap">
    <h3 class="widget-title">Recents</h3>
    <div class="widget">
      <ul>
        
          <li>
            <a href="/2016/01/30/资料/">(no title)</a>
          </li>
        
          <li>
            <a href="/2016/01/30/java/13.Classloader系列一/">ClassLoader系列一</a>
          </li>
        
          <li>
            <a href="/2016/01/29/hadoop/1.hadoop系列之源码编译/">hadoop系列一之源码编译</a>
          </li>
        
          <li>
            <a href="/2016/01/29/go/1.GO系列之入门/">Go系列一之入门</a>
          </li>
        
          <li>
            <a href="/2016/01/28/tomcat/2.tomcat性能优化/">tomcat性能优化</a>
          </li>
        
      </ul>
    </div>
  </div>

  
</aside>
        
      </div>
      <footer id="footer">
  
  <div class="outer">
    <div id="footer-info" class="inner">
      &copy; 2016 John Doe<br>
      Powered by <a href="http://hexo.io/" target="_blank">Hexo</a>
    </div>
  </div>
</footer>
    </div>
    <nav id="mobile-nav">
  
    <a href="/" class="mobile-nav-link">Home</a>
  
    <a href="/archives" class="mobile-nav-link">Archives</a>
  
</nav>
    


<script src="http://libs.baidu.com/jquery/2.0.3/jquery.min.js"></script>


  <link rel="stylesheet" href="/fancybox/jquery.fancybox.css" type="text/css">
  <script src="/fancybox/jquery.fancybox.pack.js" type="text/javascript"></script>


<script src="/js/script.js" type="text/javascript"></script>

  </div>
</body>
</html>